Merge pull request #1153 from BookStackApp/2019-design
WIP: 2019 design
| 
						 | 
				
			
			@ -103,7 +103,7 @@ class ActivityService
 | 
			
		|||
     * @param int $page
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function entityActivity($entity, $count = 20, $page = 0)
 | 
			
		||||
    public function entityActivity($entity, $count = 20, $page = 1)
 | 
			
		||||
    {
 | 
			
		||||
        if ($entity->isA('book')) {
 | 
			
		||||
            $query = $this->activity->where('book_id', '=', $entity->id);
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ class ActivityService
 | 
			
		|||
        
 | 
			
		||||
        $activity = $this->permissionService
 | 
			
		||||
            ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
 | 
			
		||||
            ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get();
 | 
			
		||||
            ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * ($page - 1))->take($count)->get();
 | 
			
		||||
 | 
			
		||||
        return $this->filterSimilar($activity);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,21 +2,26 @@
 | 
			
		|||
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use BookStack\Entities\EntityProvider;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
class ViewService
 | 
			
		||||
{
 | 
			
		||||
    protected $view;
 | 
			
		||||
    protected $permissionService;
 | 
			
		||||
    protected $entityProvider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ViewService constructor.
 | 
			
		||||
     * @param \BookStack\Actions\View $view
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionService $permissionService
 | 
			
		||||
     * @param EntityProvider $entityProvider
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(View $view, PermissionService $permissionService)
 | 
			
		||||
    public function __construct(View $view, PermissionService $permissionService, EntityProvider $entityProvider)
 | 
			
		||||
    {
 | 
			
		||||
        $this->view = $view;
 | 
			
		||||
        $this->permissionService = $permissionService;
 | 
			
		||||
        $this->entityProvider = $entityProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -50,23 +55,21 @@ class ViewService
 | 
			
		|||
     * Get the entities with the most views.
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @param Entity|false|array $filterModel
 | 
			
		||||
     * @param string|array $filterModels
 | 
			
		||||
     * @param string $action - used for permission checking
 | 
			
		||||
     * @return
 | 
			
		||||
     * @return Collection
 | 
			
		||||
     */
 | 
			
		||||
    public function getPopular($count = 10, $page = 0, $filterModel = false, $action = 'view')
 | 
			
		||||
    public function getPopular(int $count = 10, int $page = 0, $filterModels = null, string $action = 'view')
 | 
			
		||||
    {
 | 
			
		||||
        // TODO - Standardise input filter
 | 
			
		||||
        $skipCount = $count * $page;
 | 
			
		||||
        $query = $this->permissionService->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action)
 | 
			
		||||
        $query = $this->permissionService
 | 
			
		||||
            ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action)
 | 
			
		||||
            ->select('*', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
 | 
			
		||||
            ->groupBy('viewable_id', 'viewable_type')
 | 
			
		||||
            ->orderBy('view_count', 'desc');
 | 
			
		||||
 | 
			
		||||
        if ($filterModel && is_array($filterModel)) {
 | 
			
		||||
            $query->whereIn('viewable_type', $filterModel);
 | 
			
		||||
        } else if ($filterModel) {
 | 
			
		||||
            $query->where('viewable_type', '=', $filterModel->getMorphClass());
 | 
			
		||||
        if ($filterModels) {
 | 
			
		||||
            $query->whereIn('viewable_type', $this->entityProvider->getMorphClasses($filterModels));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -704,7 +704,7 @@ class PermissionService
 | 
			
		|||
     * @param string $entityIdColumn
 | 
			
		||||
     * @param string $entityTypeColumn
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     * @return QueryBuilder
 | 
			
		||||
     */
 | 
			
		||||
    public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn, $action = 'view')
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Permissions\JointPermission;
 | 
			
		||||
use BookStack\Auth\Permissions\RolePermission;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class Role extends Model
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +14,7 @@ class Role extends Model
 | 
			
		|||
     */
 | 
			
		||||
    public function users()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsToMany(User::class);
 | 
			
		||||
        return $this->belongsToMany(User::class)->orderBy('name', 'asc');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +31,7 @@ class Role extends Model
 | 
			
		|||
     */
 | 
			
		||||
    public function permissions()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsToMany(Permissions\RolePermission::class, 'permission_role', 'role_id', 'permission_id');
 | 
			
		||||
        return $this->belongsToMany(RolePermission::class, 'permission_role', 'role_id', 'permission_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -51,18 +52,18 @@ class Role extends Model
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a permission to this role.
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\RolePermission $permission
 | 
			
		||||
     * @param RolePermission $permission
 | 
			
		||||
     */
 | 
			
		||||
    public function attachPermission(Permissions\RolePermission $permission)
 | 
			
		||||
    public function attachPermission(RolePermission $permission)
 | 
			
		||||
    {
 | 
			
		||||
        $this->permissions()->attach($permission->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detach a single permission from this role.
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\RolePermission $permission
 | 
			
		||||
     * @param RolePermission $permission
 | 
			
		||||
     */
 | 
			
		||||
    public function detachPermission(Permissions\RolePermission $permission)
 | 
			
		||||
    public function detachPermission(RolePermission $permission)
 | 
			
		||||
    {
 | 
			
		||||
        $this->permissions()->detach($permission->id);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ use BookStack\Exceptions\NotFoundException;
 | 
			
		|||
use BookStack\Exceptions\UserUpdateException;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Images;
 | 
			
		||||
 | 
			
		||||
class UserRepo
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +49,7 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get all the users with their permissions.
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Builder|static
 | 
			
		||||
     * @return Builder|static
 | 
			
		||||
     */
 | 
			
		||||
    public function getAllUsers()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +60,7 @@ class UserRepo
 | 
			
		|||
     * Get all the users with their permissions in a paginated format.
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param $sortData
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Builder|static
 | 
			
		||||
     * @return Builder|static
 | 
			
		||||
     */
 | 
			
		||||
    public function getAllUsersPaginatedAndSorted($count, $sortData)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -223,16 +224,15 @@ class UserRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getRecentlyCreated(User $user, $count = 20)
 | 
			
		||||
    {
 | 
			
		||||
        $createdByUserQuery = function(Builder $query) use ($user) {
 | 
			
		||||
            $query->where('created_by', '=', $user->id);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            'pages'    => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) {
 | 
			
		||||
                $query->where('created_by', '=', $user->id);
 | 
			
		||||
            }),
 | 
			
		||||
            'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) {
 | 
			
		||||
                $query->where('created_by', '=', $user->id);
 | 
			
		||||
            }),
 | 
			
		||||
            'books'    => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) {
 | 
			
		||||
                $query->where('created_by', '=', $user->id);
 | 
			
		||||
            })
 | 
			
		||||
            'pages'    => $this->entityRepo->getRecentlyCreated('page', $count, 0, $createdByUserQuery),
 | 
			
		||||
            'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, $createdByUserQuery),
 | 
			
		||||
            'books'    => $this->entityRepo->getRecentlyCreated('book', $count, 0, $createdByUserQuery),
 | 
			
		||||
            'shelves'  => $this->entityRepo->getRecentlyCreated('bookshelf', $count, 0, $createdByUserQuery)
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -247,6 +247,7 @@ class UserRepo
 | 
			
		|||
            'pages'    => $this->entityRepo->getUserTotalCreated('page', $user),
 | 
			
		||||
            'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user),
 | 
			
		||||
            'books'    => $this->entityRepo->getUserTotalCreated('book', $user),
 | 
			
		||||
            'shelves'    => $this->entityRepo->getUserTotalCreated('bookshelf', $user),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -256,7 +257,7 @@ class UserRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getAllRoles()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->role->all();
 | 
			
		||||
        return $this->role->newQuery()->orderBy('name', 'asc')->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ class Book extends Entity
 | 
			
		|||
     */
 | 
			
		||||
    public function getBookCover($width = 440, $height = 250)
 | 
			
		||||
    {
 | 
			
		||||
        $default = baseUrl('/book_default_cover.png');
 | 
			
		||||
        $default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
 | 
			
		||||
        if (!$this->image_id) {
 | 
			
		||||
            return $default;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +69,15 @@ class Book extends Entity
 | 
			
		|||
        return $this->hasMany(Page::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the direct child pages of this book.
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
 | 
			
		||||
     */
 | 
			
		||||
    public function directPages()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->pages()->where('chapter_id', '=', '0');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get all chapters within this book.
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +101,7 @@ class Book extends Entity
 | 
			
		|||
     * @param int $length
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getExcerpt($length = 100)
 | 
			
		||||
    public function getExcerpt(int $length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        $description = $this->description;
 | 
			
		||||
        return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,8 @@ class Bookshelf extends Entity
 | 
			
		|||
     */
 | 
			
		||||
    public function getBookCover($width = 440, $height = 250)
 | 
			
		||||
    {
 | 
			
		||||
        $default = baseUrl('/book_default_cover.png');
 | 
			
		||||
        // TODO - Make generic, focused on books right now, Perhaps set-up a better image
 | 
			
		||||
        $default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
 | 
			
		||||
        if (!$this->image_id) {
 | 
			
		||||
            return $default;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +65,7 @@ class Bookshelf extends Entity
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the cover image of the book
 | 
			
		||||
     * Get the cover image of the shelf
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 | 
			
		||||
     */
 | 
			
		||||
    public function cover()
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +78,7 @@ class Bookshelf extends Entity
 | 
			
		|||
     * @param int $length
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getExcerpt($length = 100)
 | 
			
		||||
    public function getExcerpt(int $length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        $description = $this->description;
 | 
			
		||||
        return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
 | 
			
		||||
| 
						 | 
				
			
			@ -91,4 +92,14 @@ class Bookshelf extends Entity
 | 
			
		|||
    {
 | 
			
		||||
        return "'BookStack\\\\BookShelf' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if this shelf contains the given book.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function contains(Book $book)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->books()->where('id', '=', $book->id)->count() > 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use Illuminate\View\View;
 | 
			
		||||
 | 
			
		||||
class BreadcrumbsViewComposer
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected $entityContextManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * BreadcrumbsViewComposer constructor.
 | 
			
		||||
     * @param EntityContextManager $entityContextManager
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityContextManager $entityContextManager)
 | 
			
		||||
    {
 | 
			
		||||
        $this->entityContextManager = $entityContextManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Modify data when the view is composed.
 | 
			
		||||
     * @param View $view
 | 
			
		||||
     */
 | 
			
		||||
    public function compose(View $view)
 | 
			
		||||
    {
 | 
			
		||||
        $crumbs = $view->getData()['crumbs'];
 | 
			
		||||
        if (array_first($crumbs) instanceof Book) {
 | 
			
		||||
            $shelf = $this->entityContextManager->getContextualShelfForBook(array_first($crumbs));
 | 
			
		||||
            if ($shelf) {
 | 
			
		||||
                array_unshift($crumbs, $shelf);
 | 
			
		||||
                $view->with('crumbs', $crumbs);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -53,9 +53,9 @@ class Chapter extends Entity
 | 
			
		|||
     * @param int $length
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getExcerpt($length = 100)
 | 
			
		||||
    public function getExcerpt(int $length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        $description = $this->description;
 | 
			
		||||
        $description = $this->text ?? $this->description;
 | 
			
		||||
        return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,4 +67,13 @@ class Chapter extends Entity
 | 
			
		|||
    {
 | 
			
		||||
        return "'BookStack\\\\Chapter' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if this chapter has any child pages.
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function hasChildren()
 | 
			
		||||
    {
 | 
			
		||||
        return count($this->pages) > 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,6 +102,11 @@ class Entity extends Ownable
 | 
			
		|||
        return $this->morphMany(View::class, 'viewable');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function viewCountQuery()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->views()->selectRaw('viewable_id, sum(views) as view_count')->groupBy('viewable_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the Tag models that have been user assigned to this entity.
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
 | 
			
		||||
| 
						 | 
				
			
			@ -218,6 +223,20 @@ class Entity extends Ownable
 | 
			
		|||
        return $this->{$this->textField};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an excerpt of this entity's descriptive content to the specified length.
 | 
			
		||||
     * @param int $length
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getExcerpt(int $length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        $text = $this->getText();
 | 
			
		||||
        if (mb_strlen($text) > $length) {
 | 
			
		||||
            $text = mb_substr($text, 0, $length-3) . '...';
 | 
			
		||||
        }
 | 
			
		||||
        return trim($text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return a generalised, common raw query that can be 'unioned' across entities.
 | 
			
		||||
     * @return string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use Illuminate\Session\Store;
 | 
			
		||||
 | 
			
		||||
class EntityContextManager
 | 
			
		||||
{
 | 
			
		||||
    protected $session;
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
 | 
			
		||||
    protected $KEY_SHELF_CONTEXT_ID = 'context_bookshelf_id';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * EntityContextManager constructor.
 | 
			
		||||
     * @param Store $session
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Store $session, EntityRepo $entityRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->session = $session;
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the current bookshelf context for the given book.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @return Bookshelf|null
 | 
			
		||||
     */
 | 
			
		||||
    public function getContextualShelfForBook(Book $book)
 | 
			
		||||
    {
 | 
			
		||||
        $contextBookshelfId = $this->session->get($this->KEY_SHELF_CONTEXT_ID, null);
 | 
			
		||||
        if (is_int($contextBookshelfId)) {
 | 
			
		||||
 | 
			
		||||
            /** @var Bookshelf $shelf */
 | 
			
		||||
            $shelf = $this->entityRepo->getById('bookshelf', $contextBookshelfId);
 | 
			
		||||
 | 
			
		||||
            if ($shelf && $shelf->contains($book)) {
 | 
			
		||||
                return $shelf;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store the current contextual shelf ID.
 | 
			
		||||
     * @param int $shelfId
 | 
			
		||||
     */
 | 
			
		||||
    public function setShelfContext(int $shelfId)
 | 
			
		||||
    {
 | 
			
		||||
        $this->session->put($this->KEY_SHELF_CONTEXT_ID, $shelfId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear the session stored shelf context id.
 | 
			
		||||
     */
 | 
			
		||||
    public function clearShelfContext()
 | 
			
		||||
    {
 | 
			
		||||
        $this->session->forget($this->KEY_SHELF_CONTEXT_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -84,4 +84,23 @@ class EntityProvider
 | 
			
		|||
        $type = strtolower($type);
 | 
			
		||||
        return $this->all()[$type];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph classes, as an array, for a single or multiple types.
 | 
			
		||||
     * @param string|array $types
 | 
			
		||||
     * @return array<string>
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClasses($types)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_string($types)) {
 | 
			
		||||
            $types = [$types];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $morphClasses = [];
 | 
			
		||||
        foreach ($types as $type) {
 | 
			
		||||
            $model = $this->get($type);
 | 
			
		||||
            $morphClasses[] = $model->getMorphClass();
 | 
			
		||||
        }
 | 
			
		||||
        return $morphClasses;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,17 +102,6 @@ class Page extends Entity
 | 
			
		|||
        return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an excerpt of this page's content to the specified length.
 | 
			
		||||
     * @param int $length
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getExcerpt($length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        $text = strlen($this->text) > $length ? substr($this->text, 0, $length-3) . '...' : $this->text;
 | 
			
		||||
        return mb_convert_encoding($text, 'UTF-8');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return a generalised, common raw query that can be 'unioned' across entities.
 | 
			
		||||
     * @param bool $withContent
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,4 +62,5 @@ class PageRevision extends Model
 | 
			
		|||
    {
 | 
			
		||||
        return $type === 'revision';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ use BookStack\Exceptions\NotFoundException;
 | 
			
		|||
use BookStack\Exceptions\NotifyException;
 | 
			
		||||
use BookStack\Uploads\AttachmentService;
 | 
			
		||||
use DOMDocument;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,11 +180,38 @@ class EntityRepo
 | 
			
		|||
     * Get all entities in a paginated format
 | 
			
		||||
     * @param $type
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param string $sort
 | 
			
		||||
     * @param string $order
 | 
			
		||||
     * @param null|callable $queryAddition
 | 
			
		||||
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
 | 
			
		||||
     */
 | 
			
		||||
    public function getAllPaginated($type, $count = 10)
 | 
			
		||||
    public function getAllPaginated($type, int $count = 10, string $sort = 'name', string $order = 'asc', $queryAddition = null)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entityQuery($type)->orderBy('name', 'asc')->paginate($count);
 | 
			
		||||
        $query = $this->entityQuery($type);
 | 
			
		||||
        $query = $this->addSortToQuery($query, $sort, $order);
 | 
			
		||||
        if ($queryAddition) {
 | 
			
		||||
            $queryAddition($query);
 | 
			
		||||
        }
 | 
			
		||||
        return $query->paginate($count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add sorting operations to an entity query.
 | 
			
		||||
     * @param Builder $query
 | 
			
		||||
     * @param string $sort
 | 
			
		||||
     * @param string $order
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
    protected function addSortToQuery(Builder $query, string $sort = 'name', string $order = 'asc')
 | 
			
		||||
    {
 | 
			
		||||
        $order = ($order === 'asc') ? 'asc' : 'desc';
 | 
			
		||||
        $propertySorts = ['name', 'created_at', 'updated_at'];
 | 
			
		||||
 | 
			
		||||
        if (in_array($sort, $propertySorts)) {
 | 
			
		||||
            return $query->orderBy($sort, $order);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -265,15 +293,14 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the most popular entities base on all views.
 | 
			
		||||
     * @param string|bool $type
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getPopular($type, $count = 10, $page = 0)
 | 
			
		||||
    public function getPopular(string $type, int $count = 10, int $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $filter = is_bool($type) ? false : $this->entityProvider->get($type);
 | 
			
		||||
        return $this->viewService->getPopular($count, $page, $filter);
 | 
			
		||||
        return $this->viewService->getPopular($count, $page, $type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -313,6 +340,18 @@ class EntityRepo
 | 
			
		|||
        return $this->permissionService->enforceEntityRestrictions('book', $bookshelf->books())->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the direct children of a book.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Collection
 | 
			
		||||
     */
 | 
			
		||||
    public function getBookDirectChildren(Book $book)
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->permissionService->enforceEntityRestrictions('page', $book->directPages())->get();
 | 
			
		||||
        $chapters = $this->permissionService->enforceEntityRestrictions('chapters', $book->chapters())->get();
 | 
			
		||||
        return collect()->concat($pages)->concat($chapters)->sortBy('priority')->sortByDesc('draft');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get all child objects of a book.
 | 
			
		||||
     * Returns a sorted collection of Pages and Chapters.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -128,7 +128,7 @@ class LoginController extends Controller
 | 
			
		|||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return view('auth/login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
 | 
			
		||||
        return view('auth.login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ class RegisterController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function getRegisterConfirmation()
 | 
			
		||||
    {
 | 
			
		||||
        return view('auth/register-confirm');
 | 
			
		||||
        return view('auth.register-confirm');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ class RegisterController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showAwaitingConfirmation()
 | 
			
		||||
    {
 | 
			
		||||
        return view('auth/user-unconfirmed');
 | 
			
		||||
        return view('auth.user-unconfirmed');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
use Activity;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\EntityContextManager;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
| 
						 | 
				
			
			@ -15,18 +16,25 @@ class BookController extends Controller
 | 
			
		|||
    protected $entityRepo;
 | 
			
		||||
    protected $userRepo;
 | 
			
		||||
    protected $exportService;
 | 
			
		||||
    protected $entityContextManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * BookController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param ExportService $exportService
 | 
			
		||||
     * @param EntityContextManager $entityContextManager
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
 | 
			
		||||
    {
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        EntityRepo $entityRepo,
 | 
			
		||||
        UserRepo $userRepo,
 | 
			
		||||
        ExportService $exportService,
 | 
			
		||||
        EntityContextManager $entityContextManager
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
        $this->userRepo = $userRepo;
 | 
			
		||||
        $this->exportService = $exportService;
 | 
			
		||||
        $this->entityContextManager = $entityContextManager;
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,18 +44,32 @@ class BookController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        $books = $this->entityRepo->getAllPaginated('book', 18);
 | 
			
		||||
        $view = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books'));
 | 
			
		||||
        $sort = setting()->getUser($this->currentUser, 'books_sort', 'name');
 | 
			
		||||
        $order = setting()->getUser($this->currentUser, 'books_sort_order', 'asc');
 | 
			
		||||
        $sortOptions = [
 | 
			
		||||
            'name' => trans('common.sort_name'),
 | 
			
		||||
            'created_at' => trans('common.sort_created_at'),
 | 
			
		||||
            'updated_at' => trans('common.sort_updated_at'),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $books = $this->entityRepo->getAllPaginated('book', 18, $sort, $order);
 | 
			
		||||
        $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
 | 
			
		||||
        $popular = $this->entityRepo->getPopular('book', 4, 0);
 | 
			
		||||
        $new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
 | 
			
		||||
        $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
 | 
			
		||||
 | 
			
		||||
        $this->entityContextManager->clearShelfContext();
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle(trans('entities.books'));
 | 
			
		||||
        return view('books/index', [
 | 
			
		||||
        return view('books.index', [
 | 
			
		||||
            'books' => $books,
 | 
			
		||||
            'recents' => $recents,
 | 
			
		||||
            'popular' => $popular,
 | 
			
		||||
            'new' => $new,
 | 
			
		||||
            'booksViewType' => $booksViewType
 | 
			
		||||
            'view' => $view,
 | 
			
		||||
            'sort' => $sort,
 | 
			
		||||
            'order' => $order,
 | 
			
		||||
            'sortOptions' => $sortOptions,
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +81,7 @@ class BookController extends Controller
 | 
			
		|||
    {
 | 
			
		||||
        $this->checkPermission('book-create-all');
 | 
			
		||||
        $this->setPageTitle(trans('entities.books_create'));
 | 
			
		||||
        return view('books/create');
 | 
			
		||||
        return view('books.create');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -83,20 +105,28 @@ class BookController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Display the specified book.
 | 
			
		||||
     * @param $slug
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return Response
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function show($slug)
 | 
			
		||||
    public function show($slug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $this->entityRepo->getBySlug('book', $slug);
 | 
			
		||||
        $this->checkOwnablePermission('book-view', $book);
 | 
			
		||||
 | 
			
		||||
        $bookChildren = $this->entityRepo->getBookChildren($book);
 | 
			
		||||
 | 
			
		||||
        Views::add($book);
 | 
			
		||||
        if ($request->has('shelf')) {
 | 
			
		||||
            $this->entityContextManager->setShelfContext(intval($request->get('shelf')));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle($book->getShortName());
 | 
			
		||||
        return view('books/show', [
 | 
			
		||||
        return view('books.show', [
 | 
			
		||||
            'book' => $book,
 | 
			
		||||
            'current' => $book,
 | 
			
		||||
            'bookChildren' => $bookChildren,
 | 
			
		||||
            'activity' => Activity::entityActivity($book, 20, 0)
 | 
			
		||||
            'activity' => Activity::entityActivity($book, 20, 1)
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +140,7 @@ class BookController extends Controller
 | 
			
		|||
        $book = $this->entityRepo->getBySlug('book', $slug);
 | 
			
		||||
        $this->checkOwnablePermission('book-update', $book);
 | 
			
		||||
        $this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()]));
 | 
			
		||||
        return view('books/edit', ['book' => $book, 'current' => $book]);
 | 
			
		||||
        return view('books.edit', ['book' => $book, 'current' => $book]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -142,22 +172,24 @@ class BookController extends Controller
 | 
			
		|||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('book-delete', $book);
 | 
			
		||||
        $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
 | 
			
		||||
        return view('books/delete', ['book' => $book, 'current' => $book]);
 | 
			
		||||
        return view('books.delete', ['book' => $book, 'current' => $book]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shows the view which allows pages to be re-ordered and sorted.
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @return \Illuminate\View\View
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function sort($bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('book-update', $book);
 | 
			
		||||
 | 
			
		||||
        $bookChildren = $this->entityRepo->getBookChildren($book, true);
 | 
			
		||||
        $books = $this->entityRepo->getAll('book', false, 'update');
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
 | 
			
		||||
        return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
 | 
			
		||||
        return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +202,7 @@ class BookController extends Controller
 | 
			
		|||
    {
 | 
			
		||||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $bookChildren = $this->entityRepo->getBookChildren($book);
 | 
			
		||||
        return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
 | 
			
		||||
        return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -263,12 +295,12 @@ class BookController extends Controller
 | 
			
		|||
     * @param $bookSlug
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRestrict($bookSlug)
 | 
			
		||||
    public function showPermissions($bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $book);
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('books/restrictions', [
 | 
			
		||||
        return view('books.permissions', [
 | 
			
		||||
            'book' => $book,
 | 
			
		||||
            'roles' => $roles
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -277,11 +309,12 @@ class BookController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Set the restrictions for this book.
 | 
			
		||||
     * @param $bookSlug
 | 
			
		||||
     * @param $bookSlug
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function restrict($bookSlug, Request $request)
 | 
			
		||||
    public function permissions($bookSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $book);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@
 | 
			
		|||
use Activity;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\EntityContextManager;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,19 +14,19 @@ class BookshelfController extends Controller
 | 
			
		|||
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
    protected $userRepo;
 | 
			
		||||
    protected $exportService;
 | 
			
		||||
    protected $entityContextManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * BookController constructor.
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     * @param EntityContextManager $entityContextManager
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, EntityContextManager $entityContextManager)
 | 
			
		||||
    {
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
        $this->userRepo = $userRepo;
 | 
			
		||||
        $this->exportService = $exportService;
 | 
			
		||||
        $this->entityContextManager = $entityContextManager;
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,19 +36,35 @@ class BookshelfController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18);
 | 
			
		||||
        $view = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
 | 
			
		||||
        $sort = setting()->getUser($this->currentUser, 'bookshelves_sort', 'name');
 | 
			
		||||
        $order = setting()->getUser($this->currentUser, 'bookshelves_sort_order', 'asc');
 | 
			
		||||
        $sortOptions = [
 | 
			
		||||
            'name' => trans('common.sort_name'),
 | 
			
		||||
            'created_at' => trans('common.sort_created_at'),
 | 
			
		||||
            'updated_at' => trans('common.sort_updated_at'),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $sort, $order);
 | 
			
		||||
        foreach ($shelves as $shelf) {
 | 
			
		||||
            $shelf->books = $this->entityRepo->getBookshelfChildren($shelf);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false;
 | 
			
		||||
        $popular = $this->entityRepo->getPopular('bookshelf', 4, 0);
 | 
			
		||||
        $new = $this->entityRepo->getRecentlyCreated('bookshelf', 4, 0);
 | 
			
		||||
        $shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
 | 
			
		||||
 | 
			
		||||
        $this->entityContextManager->clearShelfContext();
 | 
			
		||||
        $this->setPageTitle(trans('entities.shelves'));
 | 
			
		||||
        return view('shelves/index', [
 | 
			
		||||
        return view('shelves.index', [
 | 
			
		||||
            'shelves' => $shelves,
 | 
			
		||||
            'recents' => $recents,
 | 
			
		||||
            'popular' => $popular,
 | 
			
		||||
            'new' => $new,
 | 
			
		||||
            'shelvesViewType' => $shelvesViewType
 | 
			
		||||
            'view' => $view,
 | 
			
		||||
            'sort' => $sort,
 | 
			
		||||
            'order' => $order,
 | 
			
		||||
            'sortOptions' => $sortOptions,
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +77,7 @@ class BookshelfController extends Controller
 | 
			
		|||
        $this->checkPermission('bookshelf-create-all');
 | 
			
		||||
        $books = $this->entityRepo->getAll('book', false, 'update');
 | 
			
		||||
        $this->setPageTitle(trans('entities.shelves_create'));
 | 
			
		||||
        return view('shelves/create', ['books' => $books]);
 | 
			
		||||
        return view('shelves.create', ['books' => $books]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -93,17 +109,19 @@ class BookshelfController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function show(string $slug)
 | 
			
		||||
    {
 | 
			
		||||
        $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */
 | 
			
		||||
        /** @var Bookshelf $bookshelf */
 | 
			
		||||
        $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
 | 
			
		||||
        $this->checkOwnablePermission('book-view', $bookshelf);
 | 
			
		||||
 | 
			
		||||
        $books = $this->entityRepo->getBookshelfChildren($bookshelf);
 | 
			
		||||
        Views::add($bookshelf);
 | 
			
		||||
        $this->entityContextManager->setShelfContext($bookshelf->id);
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle($bookshelf->getShortName());
 | 
			
		||||
        return view('shelves/show', [
 | 
			
		||||
        return view('shelves.show', [
 | 
			
		||||
            'shelf' => $bookshelf,
 | 
			
		||||
            'books' => $books,
 | 
			
		||||
            'activity' => Activity::entityActivity($bookshelf, 20, 0)
 | 
			
		||||
            'activity' => Activity::entityActivity($bookshelf, 20, 1)
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +144,7 @@ class BookshelfController extends Controller
 | 
			
		|||
        });
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $bookshelf->getShortName()]));
 | 
			
		||||
        return view('shelves/edit', [
 | 
			
		||||
        return view('shelves.edit', [
 | 
			
		||||
            'shelf' => $bookshelf,
 | 
			
		||||
            'books' => $books,
 | 
			
		||||
            'shelfBooks' => $shelfBooks,
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +188,7 @@ class BookshelfController extends Controller
 | 
			
		|||
        $this->checkOwnablePermission('bookshelf-delete', $bookshelf);
 | 
			
		||||
 | 
			
		||||
        $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $bookshelf->getShortName()]));
 | 
			
		||||
        return view('shelves/delete', ['shelf' => $bookshelf]);
 | 
			
		||||
        return view('shelves.delete', ['shelf' => $bookshelf]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -190,31 +208,32 @@ class BookshelfController extends Controller
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the Restrictions view.
 | 
			
		||||
     * @param $slug
 | 
			
		||||
     * Show the permissions view.
 | 
			
		||||
     * @param string $slug
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function showRestrict(string $slug)
 | 
			
		||||
    public function showPermissions(string $slug)
 | 
			
		||||
    {
 | 
			
		||||
        $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $bookshelf);
 | 
			
		||||
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('shelves.restrictions', [
 | 
			
		||||
        return view('shelves.permissions', [
 | 
			
		||||
            'shelf' => $bookshelf,
 | 
			
		||||
            'roles' => $roles
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the restrictions for this bookshelf.
 | 
			
		||||
     * @param $slug
 | 
			
		||||
     * Set the permissions for this bookshelf.
 | 
			
		||||
     * @param string $slug
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function restrict(string $slug, Request $request)
 | 
			
		||||
    public function permissions(string $slug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $bookshelf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ class ChapterController extends Controller
 | 
			
		|||
        $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('chapter-create', $book);
 | 
			
		||||
        $this->setPageTitle(trans('entities.chapters_create'));
 | 
			
		||||
        return view('chapters/create', ['book' => $book, 'current' => $book]);
 | 
			
		||||
        return view('chapters.create', ['book' => $book, 'current' => $book]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +78,7 @@ class ChapterController extends Controller
 | 
			
		|||
        Views::add($chapter);
 | 
			
		||||
        $this->setPageTitle($chapter->getShortName());
 | 
			
		||||
        $pages = $this->entityRepo->getChapterChildren($chapter);
 | 
			
		||||
        return view('chapters/show', [
 | 
			
		||||
        return view('chapters.show', [
 | 
			
		||||
            'book' => $chapter->book,
 | 
			
		||||
            'chapter' => $chapter,
 | 
			
		||||
            'current' => $chapter,
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ class ChapterController extends Controller
 | 
			
		|||
        $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('chapter-update', $chapter);
 | 
			
		||||
        $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
 | 
			
		||||
        return view('chapters/edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
			
		||||
        return view('chapters.edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ class ChapterController extends Controller
 | 
			
		|||
        $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('chapter-delete', $chapter);
 | 
			
		||||
        $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
 | 
			
		||||
        return view('chapters/delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
			
		||||
        return view('chapters.delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +162,7 @@ class ChapterController extends Controller
 | 
			
		|||
        $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
 | 
			
		||||
        $this->checkOwnablePermission('chapter-update', $chapter);
 | 
			
		||||
        $this->checkOwnablePermission('chapter-delete', $chapter);
 | 
			
		||||
        return view('chapters/move', [
 | 
			
		||||
        return view('chapters.move', [
 | 
			
		||||
            'chapter' => $chapter,
 | 
			
		||||
            'book' => $chapter->book
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -214,13 +214,14 @@ class ChapterController extends Controller
 | 
			
		|||
     * @param $bookSlug
 | 
			
		||||
     * @param $chapterSlug
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function showRestrict($bookSlug, $chapterSlug)
 | 
			
		||||
    public function showPermissions($bookSlug, $chapterSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $chapter);
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('chapters/restrictions', [
 | 
			
		||||
        return view('chapters.permissions', [
 | 
			
		||||
            'chapter' => $chapter,
 | 
			
		||||
            'roles' => $roles
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -232,8 +233,10 @@ class ChapterController extends Controller
 | 
			
		|||
     * @param $chapterSlug
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function restrict($bookSlug, $chapterSlug, Request $request)
 | 
			
		||||
    public function permissions($bookSlug, $chapterSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $chapter);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ class CommentController extends Controller
 | 
			
		|||
        $this->checkPermission('comment-create-all');
 | 
			
		||||
        $comment = $this->commentRepo->create($page, $request->only(['html', 'text', 'parent_id']));
 | 
			
		||||
        Activity::add($page, 'commented_on', $page->book->id);
 | 
			
		||||
        return view('comments/comment', ['comment' => $comment]);
 | 
			
		||||
        return view('comments.comment', ['comment' => $comment]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ class CommentController extends Controller
 | 
			
		|||
        $this->checkOwnablePermission('comment-update', $comment);
 | 
			
		||||
 | 
			
		||||
        $comment = $this->commentRepo->update($comment, $request->only(['html', 'text']));
 | 
			
		||||
        return view('comments/comment', ['comment' => $comment]);
 | 
			
		||||
        return view('comments.comment', ['comment' => $comment]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,6 +123,20 @@ abstract class Controller extends BaseController
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the current user has a permission or bypass if the provided user
 | 
			
		||||
     * id matches the current user.
 | 
			
		||||
     * @param string $permissionName
 | 
			
		||||
     * @param int $userId
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    protected function checkPermissionOrCurrentUser(string $permissionName, int $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->checkPermissionOr($permissionName, function() use ($userId) {
 | 
			
		||||
            return $userId === $this->currentUser->id;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Send back a json error message.
 | 
			
		||||
     * @param string $messageText
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,6 @@ class HomeController extends Controller
 | 
			
		|||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Display the homepage.
 | 
			
		||||
     * @return Response
 | 
			
		||||
| 
						 | 
				
			
			@ -45,17 +44,36 @@ class HomeController extends Controller
 | 
			
		|||
            'draftPages' => $draftPages,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        // Add required list ordering & sorting for books & shelves views.
 | 
			
		||||
        if ($homepageOption === 'bookshelves' || $homepageOption === 'books') {
 | 
			
		||||
            $key = $homepageOption;
 | 
			
		||||
            $view = setting()->getUser($this->currentUser, $key . '_view_type', config('app.views.' . $key));
 | 
			
		||||
            $sort = setting()->getUser($this->currentUser, $key . '_sort', 'name');
 | 
			
		||||
            $order = setting()->getUser($this->currentUser, $key . '_sort_order', 'asc');
 | 
			
		||||
 | 
			
		||||
            $sortOptions = [
 | 
			
		||||
                'name' => trans('common.sort_name'),
 | 
			
		||||
                'created_at' => trans('common.sort_created_at'),
 | 
			
		||||
                'updated_at' => trans('common.sort_updated_at'),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            $commonData = array_merge($commonData, [
 | 
			
		||||
                'view' => $view,
 | 
			
		||||
                'sort' => $sort,
 | 
			
		||||
                'order' => $order,
 | 
			
		||||
                'sortOptions' => $sortOptions,
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($homepageOption === 'bookshelves') {
 | 
			
		||||
            $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18);
 | 
			
		||||
            $shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
 | 
			
		||||
            $data = array_merge($commonData, ['shelves' => $shelves, 'shelvesViewType' => $shelvesViewType]);
 | 
			
		||||
            $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $commonData['sort'], $commonData['order']);
 | 
			
		||||
            $data = array_merge($commonData, ['shelves' => $shelves]);
 | 
			
		||||
            return view('common.home-shelves', $data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($homepageOption === 'books') {
 | 
			
		||||
            $books = $this->entityRepo->getAllPaginated('book', 18);
 | 
			
		||||
            $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
 | 
			
		||||
            $data = array_merge($commonData, ['books' => $books, 'booksViewType' => $booksViewType]);
 | 
			
		||||
            $books = $this->entityRepo->getAllPaginated('book', 18, $commonData['sort'], $commonData['order']);
 | 
			
		||||
            $data = array_merge($commonData, ['books' => $books]);
 | 
			
		||||
            return view('common.home-book', $data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +123,7 @@ class HomeController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function customHeadContent()
 | 
			
		||||
    {
 | 
			
		||||
        return view('partials/custom-head-content');
 | 
			
		||||
        return view('partials.custom-head-content');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +138,7 @@ class HomeController extends Controller
 | 
			
		|||
            $allowRobots = $sitePublic;
 | 
			
		||||
        }
 | 
			
		||||
        return response()
 | 
			
		||||
            ->view('common/robots', ['allowRobots' => $allowRobots])
 | 
			
		||||
            ->view('common.robots', ['allowRobots' => $allowRobots])
 | 
			
		||||
            ->header('Content-Type', 'text/plain');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,6 +147,6 @@ class HomeController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function getNotFound()
 | 
			
		||||
    {
 | 
			
		||||
        return response()->view('errors/404', [], 404);
 | 
			
		||||
        return response()->view('errors.404', [], 404);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        // Otherwise show the edit view if they're a guest
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_new'));
 | 
			
		||||
        return view('pages/guest-create', ['parent' => $parent]);
 | 
			
		||||
        return view('pages.guest-create', ['parent' => $parent]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ class PageController extends Controller
 | 
			
		|||
        $this->setPageTitle(trans('entities.pages_edit_draft'));
 | 
			
		||||
 | 
			
		||||
        $draftsEnabled = $this->signedIn;
 | 
			
		||||
        return view('pages/edit', [
 | 
			
		||||
        return view('pages.edit', [
 | 
			
		||||
            'page' => $draft,
 | 
			
		||||
            'book' => $draft->book,
 | 
			
		||||
            'isDraft' => true,
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +184,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        Views::add($page);
 | 
			
		||||
        $this->setPageTitle($page->getShortName());
 | 
			
		||||
        return view('pages/show', [
 | 
			
		||||
        return view('pages.show', [
 | 
			
		||||
            'page' => $page,'book' => $page->book,
 | 
			
		||||
            'current' => $page,
 | 
			
		||||
            'sidebarTree' => $sidebarTree,
 | 
			
		||||
| 
						 | 
				
			
			@ -239,7 +239,7 @@ class PageController extends Controller
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        $draftsEnabled = $this->signedIn;
 | 
			
		||||
        return view('pages/edit', [
 | 
			
		||||
        return view('pages.edit', [
 | 
			
		||||
            'page' => $page,
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
            'current' => $page,
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +317,7 @@ class PageController extends Controller
 | 
			
		|||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-delete', $page);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
        return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +333,7 @@ class PageController extends Controller
 | 
			
		|||
        $page = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
        return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -377,12 +377,13 @@ class PageController extends Controller
 | 
			
		|||
     * @param string $bookSlug
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @return \Illuminate\View\View
 | 
			
		||||
     * @throws NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function showRevisions($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
 | 
			
		||||
        return view('pages.revisions', ['page' => $page, 'current' => $page]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -403,9 +404,10 @@ class PageController extends Controller
 | 
			
		|||
        $page->fill($revision->toArray());
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
 | 
			
		||||
 | 
			
		||||
        return view('pages/revision', [
 | 
			
		||||
        return view('pages.revision', [
 | 
			
		||||
            'page' => $page,
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
            'diff' => null,
 | 
			
		||||
            'revision' => $revision
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +434,7 @@ class PageController extends Controller
 | 
			
		|||
        $page->fill($revision->toArray());
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
 | 
			
		||||
        return view('pages/revision', [
 | 
			
		||||
        return view('pages.revision', [
 | 
			
		||||
            'page' => $page,
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
            'diff' => $diff,
 | 
			
		||||
| 
						 | 
				
			
			@ -482,12 +484,12 @@ class PageController extends Controller
 | 
			
		|||
        // Check if its the latest revision, cannot delete latest revision.
 | 
			
		||||
        if (intval($currentRevision->id) === intval($revId)) {
 | 
			
		||||
            session()->flash('error', trans('entities.revision_cannot_delete_latest'));
 | 
			
		||||
            return response()->view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
 | 
			
		||||
            return response()->view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $revision->delete();
 | 
			
		||||
        session()->flash('success', trans('entities.revision_delete_success'));
 | 
			
		||||
        return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
 | 
			
		||||
        return view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -532,49 +534,20 @@ class PageController extends Controller
 | 
			
		|||
        return $this->downloadResponse($pageText, $pageSlug . '.txt');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show a listing of recently created pages
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRecentlyCreated()
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
            'title' => trans('entities.recently_created_pages'),
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show a listing of recently created pages
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRecentlyUpdated()
 | 
			
		||||
    {
 | 
			
		||||
        // TODO - Still exist?
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
        return view('pages.detailed-listing', [
 | 
			
		||||
            'title' => trans('entities.recently_updated_pages'),
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the Restrictions view.
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRestrict($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('pages/restrictions', [
 | 
			
		||||
            'page'  => $page,
 | 
			
		||||
            'roles' => $roles
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the view to choose a new parent to move a page into.
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
| 
						 | 
				
			
			@ -587,7 +560,7 @@ class PageController extends Controller
 | 
			
		|||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $this->checkOwnablePermission('page-delete', $page);
 | 
			
		||||
        return view('pages/move', [
 | 
			
		||||
        return view('pages.move', [
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
            'page' => $page
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -645,7 +618,7 @@ class PageController extends Controller
 | 
			
		|||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-view', $page);
 | 
			
		||||
        session()->flashInput(['name' => $page->name]);
 | 
			
		||||
        return view('pages/copy', [
 | 
			
		||||
        return view('pages.copy', [
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
            'page' => $page
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -690,6 +663,24 @@ class PageController extends Controller
 | 
			
		|||
        return redirect($pageCopy->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the Permissions view.
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     * @throws NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function showPermissions($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('pages.permissions', [
 | 
			
		||||
            'page'  => $page,
 | 
			
		||||
            'roles' => $roles
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the permissions for this page.
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
| 
						 | 
				
			
			@ -697,8 +688,9 @@ class PageController extends Controller
 | 
			
		|||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
			
		||||
     * @throws NotFoundException
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function restrict($bookSlug, $pageSlug, Request $request)
 | 
			
		||||
    public function permissions($bookSlug, $pageSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ class PermissionController extends Controller
 | 
			
		|||
    {
 | 
			
		||||
        $this->checkPermission('user-roles-manage');
 | 
			
		||||
        $roles = $this->permissionsRepo->getAllRoles();
 | 
			
		||||
        return view('settings/roles/index', ['roles' => $roles]);
 | 
			
		||||
        return view('settings.roles.index', ['roles' => $roles]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ class PermissionController extends Controller
 | 
			
		|||
    public function createRole()
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermission('user-roles-manage');
 | 
			
		||||
        return view('settings/roles/create');
 | 
			
		||||
        return view('settings.roles.create');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ class PermissionController extends Controller
 | 
			
		|||
        if ($role->hidden) {
 | 
			
		||||
            throw new PermissionsException(trans('errors.role_cannot_be_edited'));
 | 
			
		||||
        }
 | 
			
		||||
        return view('settings/roles/edit', ['role' => $role]);
 | 
			
		||||
        return view('settings.roles.edit', ['role' => $role]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ class PermissionController extends Controller
 | 
			
		|||
        $roles = $this->permissionsRepo->getAllRolesExcept($role);
 | 
			
		||||
        $blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]);
 | 
			
		||||
        $roles->prepend($blankRole);
 | 
			
		||||
        return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]);
 | 
			
		||||
        return view('settings.roles.delete', ['role' => $role, 'roles' => $roles]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,45 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Actions\ViewService;
 | 
			
		||||
use BookStack\Entities\EntityContextManager;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\SearchService;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use Illuminate\Contracts\View\Factory;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\View\View;
 | 
			
		||||
 | 
			
		||||
class SearchController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
    protected $viewService;
 | 
			
		||||
    protected $searchService;
 | 
			
		||||
    protected $entityContextManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SearchController constructor.
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param ViewService $viewService
 | 
			
		||||
     * @param SearchService $searchService
 | 
			
		||||
     * @param EntityContextManager $entityContextManager
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, ViewService $viewService, SearchService $searchService)
 | 
			
		||||
    {
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        EntityRepo $entityRepo,
 | 
			
		||||
        ViewService $viewService,
 | 
			
		||||
        SearchService $searchService,
 | 
			
		||||
        EntityContextManager $entityContextManager
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
        $this->viewService = $viewService;
 | 
			
		||||
        $this->searchService = $searchService;
 | 
			
		||||
        $this->entityContextManager = $entityContextManager;
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Searches all entities.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\View\View
 | 
			
		||||
     * @return View
 | 
			
		||||
     * @internal param string $searchTerm
 | 
			
		||||
     */
 | 
			
		||||
    public function search(Request $request)
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +52,7 @@ class SearchController extends Controller
 | 
			
		|||
 | 
			
		||||
        $results = $this->searchService->searchEntities($searchTerm, 'all', $page, 20);
 | 
			
		||||
 | 
			
		||||
        return view('search/all', [
 | 
			
		||||
        return view('search.all', [
 | 
			
		||||
            'entities'   => $results['results'],
 | 
			
		||||
            'totalResults' => $results['total'],
 | 
			
		||||
            'searchTerm' => $searchTerm,
 | 
			
		||||
| 
						 | 
				
			
			@ -55,28 +66,28 @@ class SearchController extends Controller
 | 
			
		|||
     * Searches all entities within a book.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param integer $bookId
 | 
			
		||||
     * @return \Illuminate\View\View
 | 
			
		||||
     * @return View
 | 
			
		||||
     * @internal param string $searchTerm
 | 
			
		||||
     */
 | 
			
		||||
    public function searchBook(Request $request, $bookId)
 | 
			
		||||
    {
 | 
			
		||||
        $term = $request->get('term', '');
 | 
			
		||||
        $results = $this->searchService->searchBook($bookId, $term);
 | 
			
		||||
        return view('partials/entity-list', ['entities' => $results]);
 | 
			
		||||
        return view('partials.entity-list', ['entities' => $results]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Searches all entities within a chapter.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param integer $chapterId
 | 
			
		||||
     * @return \Illuminate\View\View
 | 
			
		||||
     * @return View
 | 
			
		||||
     * @internal param string $searchTerm
 | 
			
		||||
     */
 | 
			
		||||
    public function searchChapter(Request $request, $chapterId)
 | 
			
		||||
    {
 | 
			
		||||
        $term = $request->get('term', '');
 | 
			
		||||
        $results = $this->searchService->searchChapter($chapterId, $term);
 | 
			
		||||
        return view('partials/entity-list', ['entities' => $results]);
 | 
			
		||||
        return view('partials.entity-list', ['entities' => $results]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -87,21 +98,64 @@ class SearchController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function searchEntitiesAjax(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $entityTypes = $request->filled('types') ? collect(explode(',', $request->get('types'))) : collect(['page', 'chapter', 'book']);
 | 
			
		||||
        $entityTypes = $request->filled('types') ? explode(',', $request->get('types')) : ['page', 'chapter', 'book'];
 | 
			
		||||
        $searchTerm =  $request->get('term', false);
 | 
			
		||||
        $permission = $request->get('permission', 'view');
 | 
			
		||||
 | 
			
		||||
        // Search for entities otherwise show most popular
 | 
			
		||||
        if ($searchTerm !== false) {
 | 
			
		||||
            $searchTerm .= ' {type:'. implode('|', $entityTypes->toArray()) .'}';
 | 
			
		||||
            $searchTerm .= ' {type:'. implode('|', $entityTypes) .'}';
 | 
			
		||||
            $entities = $this->searchService->searchEntities($searchTerm, 'all', 1, 20, $permission)['results'];
 | 
			
		||||
        } else {
 | 
			
		||||
            $entityNames = $entityTypes->map(function ($type) {
 | 
			
		||||
                return 'BookStack\\' . ucfirst($type); // TODO - Extract this elsewhere, too specific and stringy
 | 
			
		||||
            })->toArray();
 | 
			
		||||
            $entities = $this->viewService->getPopular(20, 0, $entityNames, $permission);
 | 
			
		||||
            $entities = $this->viewService->getPopular(20, 0, $entityTypes, $permission);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return view('search/entity-ajax-list', ['entities' => $entities]);
 | 
			
		||||
        return view('search.entity-ajax-list', ['entities' => $entities]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search siblings items in the system.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return Factory|View|mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function searchSiblings(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $type = $request->get('entity_type', null);
 | 
			
		||||
        $id = $request->get('entity_id', null);
 | 
			
		||||
 | 
			
		||||
        $entity = $this->entityRepo->getById($type, $id);
 | 
			
		||||
        if (!$entity) {
 | 
			
		||||
            return $this->jsonError(trans('errors.entity_not_found'), 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $entities = [];
 | 
			
		||||
 | 
			
		||||
        // Page in chapter
 | 
			
		||||
        if ($entity->isA('page') && $entity->chapter) {
 | 
			
		||||
            $entities = $this->entityRepo->getChapterChildren($entity->chapter);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Page in book or chapter
 | 
			
		||||
        if (($entity->isA('page') && !$entity->chapter) || $entity->isA('chapter')) {
 | 
			
		||||
            $entities = $this->entityRepo->getBookDirectChildren($entity->book);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Book
 | 
			
		||||
        // Gets just the books in a shelf if shelf is in context
 | 
			
		||||
        if ($entity->isA('book')) {
 | 
			
		||||
            $contextShelf = $this->entityContextManager->getContextualShelfForBook($entity);
 | 
			
		||||
            if ($contextShelf) {
 | 
			
		||||
                $entities = $this->entityRepo->getBookshelfChildren($contextShelf);
 | 
			
		||||
            } else {
 | 
			
		||||
                $entities = $this->entityRepo->getAll('book');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Shelve
 | 
			
		||||
        if ($entity->isA('bookshelf')) {
 | 
			
		||||
            $entities = $this->entityRepo->getAll('bookshelf');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return view('partials.entity-list-basic', ['entities' => $entities, 'style' => 'compact']);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,10 @@ class SettingController extends Controller
 | 
			
		|||
        // Get application version
 | 
			
		||||
        $version = trim(file_get_contents(base_path('version')));
 | 
			
		||||
 | 
			
		||||
        return view('settings/index', ['version' => $version]);
 | 
			
		||||
        return view('settings.index', [
 | 
			
		||||
            'version' => $version,
 | 
			
		||||
            'guestUser' => User::getDefault()
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +61,7 @@ class SettingController extends Controller
 | 
			
		|||
        // Get application version
 | 
			
		||||
        $version = trim(file_get_contents(base_path('version')));
 | 
			
		||||
 | 
			
		||||
        return view('settings/maintenance', ['version' => $version]);
 | 
			
		||||
        return view('settings.maintenance', ['version' => $version]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ class UserController extends Controller
 | 
			
		|||
        $users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails);
 | 
			
		||||
        $this->setPageTitle(trans('settings.users'));
 | 
			
		||||
        $users->appends($listDetails);
 | 
			
		||||
        return view('users/index', ['users' => $users, 'listDetails' => $listDetails]);
 | 
			
		||||
        return view('users.index', ['users' => $users, 'listDetails' => $listDetails]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ class UserController extends Controller
 | 
			
		|||
        $this->checkPermission('users-manage');
 | 
			
		||||
        $authMethod = config('auth.method');
 | 
			
		||||
        $roles = $this->userRepo->getAllRoles();
 | 
			
		||||
        return view('users/create', ['authMethod' => $authMethod, 'roles' => $roles]);
 | 
			
		||||
        return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ class UserController extends Controller
 | 
			
		|||
        $activeSocialDrivers = $socialAuthService->getActiveDrivers();
 | 
			
		||||
        $this->setPageTitle(trans('settings.user_profile'));
 | 
			
		||||
        $roles = $this->userRepo->getAllRoles();
 | 
			
		||||
        return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
 | 
			
		||||
        return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +190,7 @@ class UserController extends Controller
 | 
			
		|||
 | 
			
		||||
        $user = $this->userRepo->getById($id);
 | 
			
		||||
        $this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name]));
 | 
			
		||||
        return view('users/delete', ['user' => $user]);
 | 
			
		||||
        return view('users.delete', ['user' => $user]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -232,10 +232,12 @@ class UserController extends Controller
 | 
			
		|||
    public function showProfilePage($id)
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->userRepo->getById($id);
 | 
			
		||||
 | 
			
		||||
        $userActivity = $this->userRepo->getActivity($user);
 | 
			
		||||
        $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
 | 
			
		||||
        $assetCounts = $this->userRepo->getAssetCounts($user);
 | 
			
		||||
        return view('users/profile', [
 | 
			
		||||
 | 
			
		||||
        return view('users.profile', [
 | 
			
		||||
            'user' => $user,
 | 
			
		||||
            'activity' => $userActivity,
 | 
			
		||||
            'recentlyCreated' => $recentlyCreated,
 | 
			
		||||
| 
						 | 
				
			
			@ -251,19 +253,7 @@ class UserController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function switchBookView($id, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
			
		||||
            return $this->currentUser->id == $id;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $viewType = $request->get('view_type');
 | 
			
		||||
        if (!in_array($viewType, ['grid', 'list'])) {
 | 
			
		||||
            $viewType = 'list';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = $this->user->findOrFail($id);
 | 
			
		||||
        setting()->putUser($user, 'books_view_type', $viewType);
 | 
			
		||||
 | 
			
		||||
        return redirect()->back(302, [], "/settings/users/$id");
 | 
			
		||||
        return $this->switchViewType($id, $request, 'books');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -274,18 +264,98 @@ class UserController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function switchShelfView($id, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
			
		||||
            return $this->currentUser->id == $id;
 | 
			
		||||
        });
 | 
			
		||||
        return $this->switchViewType($id, $request, 'bookshelves');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * For a type of list, switch with stored view type for a user.
 | 
			
		||||
     * @param integer $userId
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param string $listName
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse
 | 
			
		||||
     */
 | 
			
		||||
    protected function switchViewType($userId, Request $request, string $listName)
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermissionOrCurrentUser('users-manage', $userId);
 | 
			
		||||
 | 
			
		||||
        $viewType = $request->get('view_type');
 | 
			
		||||
        if (!in_array($viewType, ['grid', 'list'])) {
 | 
			
		||||
            $viewType = 'list';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = $this->userRepo->getById($id);
 | 
			
		||||
        setting()->putUser($user, 'bookshelves_view_type', $viewType);
 | 
			
		||||
        $user = $this->userRepo->getById($userId);
 | 
			
		||||
        $key = $listName . '_view_type';
 | 
			
		||||
        setting()->putUser($user, $key, $viewType);
 | 
			
		||||
 | 
			
		||||
        return redirect()->back(302, [], "/settings/users/$id");
 | 
			
		||||
        return redirect()->back(302, [], "/settings/users/$userId");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Change the stored sort type for a particular view.
 | 
			
		||||
     * @param string $id
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse
 | 
			
		||||
     */
 | 
			
		||||
    public function changeSort(string $id, string $type, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $validSortTypes = ['books', 'bookshelves'];
 | 
			
		||||
        if (!in_array($type, $validSortTypes)) {
 | 
			
		||||
            return redirect()->back(500);
 | 
			
		||||
        }
 | 
			
		||||
        return $this->changeListSort($id, $request, $type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update the stored section expansion preference for the given user.
 | 
			
		||||
     * @param string $id
 | 
			
		||||
     * @param string $key
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
 | 
			
		||||
     */
 | 
			
		||||
    public function updateExpansionPreference(string $id, string $key, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermissionOrCurrentUser('users-manage', $id);
 | 
			
		||||
        $keyWhitelist = ['home-details'];
 | 
			
		||||
        if (!in_array($key, $keyWhitelist)) {
 | 
			
		||||
            return response("Invalid key", 500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $newState = $request->get('expand', 'false');
 | 
			
		||||
 | 
			
		||||
        $user = $this->user->findOrFail($id);
 | 
			
		||||
        setting()->putUser($user, 'section_expansion#' . $key, $newState);
 | 
			
		||||
        return response("", 204);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Changed the stored preference for a list sort order.
 | 
			
		||||
     * @param int $userId
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param string $listName
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse
 | 
			
		||||
     */
 | 
			
		||||
    protected function changeListSort(int $userId, Request $request, string $listName)
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkPermissionOrCurrentUser('users-manage', $userId);
 | 
			
		||||
 | 
			
		||||
        $sort = $request->get('sort');
 | 
			
		||||
        if (!in_array($sort, ['name', 'created_at', 'updated_at'])) {
 | 
			
		||||
            $sort = 'name';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $order = $request->get('order');
 | 
			
		||||
        if (!in_array($order, ['asc', 'desc'])) {
 | 
			
		||||
            $order = 'asc';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = $this->user->findOrFail($userId);
 | 
			
		||||
        $sortKey = $listName . '_sort';
 | 
			
		||||
        $orderKey = $listName . '_sort_order';
 | 
			
		||||
        setting()->putUser($user, $sortKey, $sort);
 | 
			
		||||
        setting()->putUser($user, $orderKey, $order);
 | 
			
		||||
 | 
			
		||||
        return redirect()->back(302, [], "/settings/users/$userId");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ class Authenticate
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->auth->guest() && !setting('app-public')) {
 | 
			
		||||
        if (!hasAppAccess()) {
 | 
			
		||||
            if ($request->ajax()) {
 | 
			
		||||
                return response('Unauthorized.', 401);
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,12 +3,14 @@
 | 
			
		|||
use Blade;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\BreadcrumbsViewComposer;
 | 
			
		||||
use BookStack\Entities\Chapter;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Settings\Setting;
 | 
			
		||||
use BookStack\Settings\SettingService;
 | 
			
		||||
use Illuminate\Database\Eloquent\Relations\Relation;
 | 
			
		||||
use Illuminate\Http\UploadedFile;
 | 
			
		||||
use Illuminate\Support\Facades\View;
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
use Schema;
 | 
			
		||||
use Validator;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +35,6 @@ class AppServiceProvider extends ServiceProvider
 | 
			
		|||
            return substr_count($uploadName, '.') < 2;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Custom blade view directives
 | 
			
		||||
        Blade::directive('icon', function ($expression) {
 | 
			
		||||
            return "<?php echo icon($expression); ?>";
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +50,9 @@ class AppServiceProvider extends ServiceProvider
 | 
			
		|||
            'BookStack\\Chapter' => Chapter::class,
 | 
			
		||||
            'BookStack\\Page' => Page::class,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // View Composers
 | 
			
		||||
        View::composer('partials.breadcrumbs', BreadcrumbsViewComposer::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,20 +2,11 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Actions\Activity;
 | 
			
		||||
use BookStack\Actions\ActivityService;
 | 
			
		||||
use BookStack\Actions\View;
 | 
			
		||||
use BookStack\Actions\ViewService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Settings\Setting;
 | 
			
		||||
use BookStack\Settings\SettingService;
 | 
			
		||||
use BookStack\Uploads\HttpFetcher;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
use Illuminate\Contracts\Cache\Repository;
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Factory;
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
use Intervention\Image\ImageManager;
 | 
			
		||||
 | 
			
		||||
class CustomFacadeProvider extends ServiceProvider
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -37,34 +28,19 @@ class CustomFacadeProvider extends ServiceProvider
 | 
			
		|||
    public function register()
 | 
			
		||||
    {
 | 
			
		||||
        $this->app->bind('activity', function () {
 | 
			
		||||
            return new ActivityService(
 | 
			
		||||
                $this->app->make(Activity::class),
 | 
			
		||||
                $this->app->make(PermissionService::class)
 | 
			
		||||
            );
 | 
			
		||||
            return $this->app->make(ActivityService::class);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->app->bind('views', function () {
 | 
			
		||||
            return new ViewService(
 | 
			
		||||
                $this->app->make(View::class),
 | 
			
		||||
                $this->app->make(PermissionService::class)
 | 
			
		||||
            );
 | 
			
		||||
            return $this->app->make(ViewService::class);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->app->bind('setting', function () {
 | 
			
		||||
            return new SettingService(
 | 
			
		||||
                $this->app->make(Setting::class),
 | 
			
		||||
                $this->app->make(Repository::class)
 | 
			
		||||
            );
 | 
			
		||||
            return $this->app->make(SettingService::class);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->app->bind('images', function () {
 | 
			
		||||
            return new ImageService(
 | 
			
		||||
                $this->app->make(Image::class),
 | 
			
		||||
                $this->app->make(ImageManager::class),
 | 
			
		||||
                $this->app->make(Factory::class),
 | 
			
		||||
                $this->app->make(Repository::class),
 | 
			
		||||
                $this->app->make(HttpFetcher::class)
 | 
			
		||||
            );
 | 
			
		||||
            return $this->app->make(ImageService::class);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,9 +61,23 @@ class SettingService
 | 
			
		|||
     */
 | 
			
		||||
    public function getUser($user, $key, $default = false)
 | 
			
		||||
    {
 | 
			
		||||
        if ($user->isDefault()) {
 | 
			
		||||
            return session()->get($key, $default);
 | 
			
		||||
        }
 | 
			
		||||
        return $this->get($this->userKey($user->id, $key), $default);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a value for the current logged-in user.
 | 
			
		||||
     * @param $key
 | 
			
		||||
     * @param bool $default
 | 
			
		||||
     * @return bool|string
 | 
			
		||||
     */
 | 
			
		||||
    public function getForCurrentUser($key, $default = false)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->getUser(user(), $key, $default);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a setting value from the cache or database.
 | 
			
		||||
     * Looks at the system defaults if not cached or in database.
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +194,9 @@ class SettingService
 | 
			
		|||
     */
 | 
			
		||||
    public function putUser($user, $key, $value)
 | 
			
		||||
    {
 | 
			
		||||
        if ($user->isDefault()) {
 | 
			
		||||
            return session()->put($key, $value);
 | 
			
		||||
        }
 | 
			
		||||
        return $this->put($this->userKey($user->id, $key), $value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,11 +43,19 @@ function user()
 | 
			
		|||
 * Check if current user is a signed in user.
 | 
			
		||||
 * @return bool
 | 
			
		||||
 */
 | 
			
		||||
function signedInUser()
 | 
			
		||||
function signedInUser() : bool
 | 
			
		||||
{
 | 
			
		||||
    return auth()->user() && !auth()->user()->isDefault();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if the current user has general access.
 | 
			
		||||
 * @return bool
 | 
			
		||||
 */
 | 
			
		||||
function hasAppAccess() : bool {
 | 
			
		||||
    return !auth()->guest() || setting('app-public');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if the current user has a permission.
 | 
			
		||||
 * If an ownable element is passed in the jointPermissions are checked against
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								package.json
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -13,17 +13,17 @@
 | 
			
		|||
    "@babel/core": "^7.1.6",
 | 
			
		||||
    "@babel/polyfill": "^7.0.0",
 | 
			
		||||
    "@babel/preset-env": "^7.1.6",
 | 
			
		||||
    "autoprefixer": "^8.6.5",
 | 
			
		||||
    "autoprefixer": "^9.4.7",
 | 
			
		||||
    "babel-loader": "^8.0.4",
 | 
			
		||||
    "css-loader": "^0.28.11",
 | 
			
		||||
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
 | 
			
		||||
    "css-loader": "^2.1.0",
 | 
			
		||||
    "livereload": "^0.7.0",
 | 
			
		||||
    "mini-css-extract-plugin": "^0.5.0",
 | 
			
		||||
    "node-sass": "^4.10.0",
 | 
			
		||||
    "npm-run-all": "^4.1.5",
 | 
			
		||||
    "postcss-loader": "^2.1.6",
 | 
			
		||||
    "postcss-loader": "^3.0.0",
 | 
			
		||||
    "sass-loader": "^7.1.0",
 | 
			
		||||
    "style-loader": "^0.21.0",
 | 
			
		||||
    "uglifyjs-webpack-plugin": "^1.3.0",
 | 
			
		||||
    "style-loader": "^0.23.1",
 | 
			
		||||
    "uglifyjs-webpack-plugin": "^2.1.1",
 | 
			
		||||
    "webpack": "^4.26.1",
 | 
			
		||||
    "webpack-cli": "^3.1.2"
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1 @@
 | 
			
		|||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
    <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
 | 
			
		||||
    <path d="M0 0h24v24H0z" fill="none"/>
 | 
			
		||||
</svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 13.3h-5.7V19h-2.6v-5.7H5v-2.6h5.7V5h2.6v5.7H19z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 166 B  | 
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   viewBox="0 0 24 24"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg6"
 | 
			
		||||
   sodipodi:docname="books.svg"
 | 
			
		||||
   inkscape:version="0.92.3 (2405546, 2018-03-11)">
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata12">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs10" />
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     objecttolerance="10"
 | 
			
		||||
     gridtolerance="10"
 | 
			
		||||
     guidetolerance="10"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1413"
 | 
			
		||||
     id="namedview8"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:zoom="19.666667"
 | 
			
		||||
     inkscape:cx="13.076733"
 | 
			
		||||
     inkscape:cy="8.7801453"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     inkscape:current-layer="svg6" />
 | 
			
		||||
  <path
 | 
			
		||||
     d="M0 0h24v24H0z"
 | 
			
		||||
     fill="none"
 | 
			
		||||
     id="path2" />
 | 
			
		||||
  <path
 | 
			
		||||
     d="M 19.252119,1.707627 H 8.6631356 c -0.9706568,0 -1.7648305,0.7941737 -1.7648305,1.7648305 V 17.591101 c 0,0.970657 0.7941737,1.764831 1.7648305,1.764831 H 19.252119 c 0.970656,0 1.76483,-0.794174 1.76483,-1.764831 V 3.4724575 c 0,-0.9706568 -0.794174,-1.7648305 -1.76483,-1.7648305 z M 8.6631356,3.4724575 H 13.075212 V 10.531779 L 10.869173,9.2081571 8.6631356,10.531779 Z"
 | 
			
		||||
     id="path4"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="stroke-width:0.88241524" />
 | 
			
		||||
  <g
 | 
			
		||||
     id="g836"
 | 
			
		||||
     transform="translate(30.610169,3.2033898)">
 | 
			
		||||
    <path
 | 
			
		||||
       id="path822"
 | 
			
		||||
       d="M 0,0 H 24 V 24 H 0 Z"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       style="fill:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path824"
 | 
			
		||||
       d="M -27.644068,3.4067797 V 17.40678 c 0,1.1 0.9,2 2,2 h 14 v -2 h -14 V 3.4067797 Z"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       sodipodi:nodetypes="cssccccc" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
						 | 
				
			
			@ -1,2 +1 @@
 | 
			
		|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M1.088 2.566h17.42v17.42H1.088z" fill="none"/><path d="M4 20.058h15.892V22H4z"/><path d="M2.902 1.477h17.42v17.42H2.903z" fill="none"/><g><path d="M6.658 3.643V18h-2.38V3.643zM11.326 3.643V18H8.947V3.643zM14.722 3.856l5.613 13.214-2.19.93-5.613-13.214z"/></g></svg>
 | 
			
		||||
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M1.088 2.566h17.42v17.42H1.088z" fill="none"/><path d="M4 20.058h15.892V22H4z"/><path d="M2.902 1.477h17.42v17.42H2.903z" fill="none"/><g><path d="M6.658 3.643V18h-2.38V3.643zM11.326 3.643V18H8.947V3.643zM14.722 3.856l5.613 13.214-2.19.93-5.613-13.214z"/></g></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 373 B  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.86 4.118l-9.733 9.609-3.951-3.995-2.98 2.966 6.93 7.184L21.805 7.217z"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 151 B  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 161 B  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 21.034l6.57-6.554h-4.927V2.966h-3.286V14.48H5.43z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 168 B  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2.966L5.43 9.52h4.927v11.514h3.286V9.52h4.927z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 165 B  | 
| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class BreadcrumbListing {
 | 
			
		||||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
        this.searchInput = elem.querySelector('input');
 | 
			
		||||
        this.loadingElem = elem.querySelector('.loading-container');
 | 
			
		||||
        this.entityListElem = elem.querySelector('.breadcrumb-listing-entity-list');
 | 
			
		||||
        this.toggleElem = elem.querySelector('[dropdown-toggle]');
 | 
			
		||||
 | 
			
		||||
        // this.loadingElem.style.display = 'none';
 | 
			
		||||
        const entityDescriptor = elem.getAttribute('breadcrumb-listing').split(':');
 | 
			
		||||
        this.entityType = entityDescriptor[0];
 | 
			
		||||
        this.entityId = Number(entityDescriptor[1]);
 | 
			
		||||
 | 
			
		||||
        this.toggleElem.addEventListener('click', this.onShow.bind(this));
 | 
			
		||||
        this.searchInput.addEventListener('input', this.onSearch.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onShow() {
 | 
			
		||||
        this.loadEntityView();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onSearch() {
 | 
			
		||||
        const input = this.searchInput.value.toLowerCase().trim();
 | 
			
		||||
        const listItems = this.entityListElem.querySelectorAll('.entity-list-item');
 | 
			
		||||
        for (let listItem of listItems) {
 | 
			
		||||
            const match = !input || listItem.textContent.toLowerCase().includes(input);
 | 
			
		||||
            listItem.style.display = match ? 'flex' : 'none';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    loadEntityView() {
 | 
			
		||||
        this.toggleLoading(true);
 | 
			
		||||
 | 
			
		||||
        const params = {
 | 
			
		||||
            'entity_id': this.entityId,
 | 
			
		||||
            'entity_type': this.entityType,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        window.$http.get('/search/entity/siblings', {params}).then(resp => {
 | 
			
		||||
            this.entityListElem.innerHTML = resp.data;
 | 
			
		||||
        }).catch(err => {
 | 
			
		||||
            console.error(err);
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            this.toggleLoading(false);
 | 
			
		||||
            this.onSearch();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleLoading(show = false) {
 | 
			
		||||
        this.loadingElem.style.display = show ? 'block' : 'none';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default BreadcrumbListing;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ class DropDown {
 | 
			
		|||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.container = elem;
 | 
			
		||||
        this.menu = elem.querySelector('ul');
 | 
			
		||||
        this.menu = elem.querySelector('ul, [dropdown-menu]');
 | 
			
		||||
        this.toggle = elem.querySelector('[dropdown-toggle]');
 | 
			
		||||
        this.setupListeners();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,15 +5,17 @@ class EntitySelector {
 | 
			
		|||
        this.elem = elem;
 | 
			
		||||
        this.search = '';
 | 
			
		||||
        this.lastClick = 0;
 | 
			
		||||
        this.selectedItemData = null;
 | 
			
		||||
 | 
			
		||||
        let entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
 | 
			
		||||
        let entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
 | 
			
		||||
        const entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
 | 
			
		||||
        const entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
 | 
			
		||||
        this.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}&permission=${encodeURIComponent(entityPermission)}`);
 | 
			
		||||
 | 
			
		||||
        this.input = elem.querySelector('[entity-selector-input]');
 | 
			
		||||
        this.searchInput = elem.querySelector('[entity-selector-search]');
 | 
			
		||||
        this.loading = elem.querySelector('[entity-selector-loading]');
 | 
			
		||||
        this.resultsContainer = elem.querySelector('[entity-selector-results]');
 | 
			
		||||
        this.addButton = elem.querySelector('[entity-selector-add-button]');
 | 
			
		||||
 | 
			
		||||
        this.elem.addEventListener('click', this.onClick.bind(this));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,10 +28,20 @@ class EntitySelector {
 | 
			
		|||
                this.searchEntities(this.searchInput.value);
 | 
			
		||||
            }, 200);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.searchInput.addEventListener('keydown', event => {
 | 
			
		||||
            if (event.keyCode === 13) event.preventDefault();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (this.addButton) {
 | 
			
		||||
            this.addButton.addEventListener('click', event => {
 | 
			
		||||
                if (this.selectedItemData) {
 | 
			
		||||
                    this.confirmSelection(this.selectedItemData);
 | 
			
		||||
                    this.unselectAll();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.showLoading();
 | 
			
		||||
        this.initialLoad();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +65,7 @@ class EntitySelector {
 | 
			
		|||
 | 
			
		||||
    searchEntities(searchTerm) {
 | 
			
		||||
        this.input.value = '';
 | 
			
		||||
        let url = this.searchUrl + `&term=${encodeURIComponent(searchTerm)}`;
 | 
			
		||||
        let url = `${this.searchUrl}&term=${encodeURIComponent(searchTerm)}`;
 | 
			
		||||
        window.$http.get(url).then(resp => {
 | 
			
		||||
            this.resultsContainer.innerHTML = resp.data;
 | 
			
		||||
            this.hideLoading();
 | 
			
		||||
| 
						 | 
				
			
			@ -68,49 +80,54 @@ class EntitySelector {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    onClick(event) {
 | 
			
		||||
        let t = event.target;
 | 
			
		||||
 | 
			
		||||
        if (t.matches('.entity-list-item  *')) {
 | 
			
		||||
        const listItem = event.target.closest('[data-entity-type]');
 | 
			
		||||
        if (listItem) {
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            event.stopPropagation();
 | 
			
		||||
            let item = t.closest('[data-entity-type]');
 | 
			
		||||
            this.selectItem(item);
 | 
			
		||||
        } else if (t.matches('[data-entity-type]')) {
 | 
			
		||||
            this.selectItem(t)
 | 
			
		||||
            this.selectItem(listItem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    selectItem(item) {
 | 
			
		||||
        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;
 | 
			
		||||
        const isDblClick = this.isDoubleClick();
 | 
			
		||||
        const type = item.getAttribute('data-entity-type');
 | 
			
		||||
        const id = item.getAttribute('data-entity-id');
 | 
			
		||||
        const isSelected = (!item.classList.contains('selected') || isDblClick);
 | 
			
		||||
 | 
			
		||||
        this.unselectAll();
 | 
			
		||||
        this.input.value = isSelected ? `${type}:${id}` : '';
 | 
			
		||||
 | 
			
		||||
        if (!isSelected) window.$events.emit('entity-select-change', null);
 | 
			
		||||
        const link = item.getAttribute('href');
 | 
			
		||||
        const name = item.querySelector('.entity-list-item-name').textContent;
 | 
			
		||||
        const data = {id: Number(id), name: name, link: link};
 | 
			
		||||
 | 
			
		||||
        if (isSelected) {
 | 
			
		||||
            item.classList.add('selected');
 | 
			
		||||
            item.classList.add('primary-background');
 | 
			
		||||
            this.selectedItemData = data;
 | 
			
		||||
        } else {
 | 
			
		||||
            window.$events.emit('entity-select-change', null)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!isDblClick && !isSelected) return;
 | 
			
		||||
 | 
			
		||||
        let link = item.querySelector('.entity-list-item-link').getAttribute('href');
 | 
			
		||||
        let name = item.querySelector('.entity-list-item-name').textContent;
 | 
			
		||||
        let data = {id: Number(id), name: name, link: link};
 | 
			
		||||
        if (isDblClick) {
 | 
			
		||||
            this.confirmSelection(data);
 | 
			
		||||
        }
 | 
			
		||||
        if (isSelected) {
 | 
			
		||||
            window.$events.emit('entity-select-change', data)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (isDblClick) window.$events.emit('entity-select-confirm', data);
 | 
			
		||||
        if (isSelected) window.$events.emit('entity-select-change', data);
 | 
			
		||||
    confirmSelection(data) {
 | 
			
		||||
        window.$events.emit('entity-select-confirm', data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unselectAll() {
 | 
			
		||||
        let selected = this.elem.querySelectorAll('.selected');
 | 
			
		||||
        for (let i = 0, len = selected.length; i < len; i++) {
 | 
			
		||||
            selected[i].classList.remove('selected');
 | 
			
		||||
            selected[i].classList.remove('primary-background');
 | 
			
		||||
        for (let selectedElem of selected) {
 | 
			
		||||
            selectedElem.classList.remove('selected', 'primary-background');
 | 
			
		||||
        }
 | 
			
		||||
        this.selectedItemData = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,13 @@ class ExpandToggle {
 | 
			
		|||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
        this.isOpen = false;
 | 
			
		||||
 | 
			
		||||
        // Component state
 | 
			
		||||
        this.isOpen = elem.getAttribute('expand-toggle-is-open') === 'yes';
 | 
			
		||||
        this.updateEndpoint = elem.getAttribute('expand-toggle-update-endpoint');
 | 
			
		||||
        this.selector = elem.getAttribute('expand-toggle');
 | 
			
		||||
 | 
			
		||||
        // Listener setup
 | 
			
		||||
        elem.addEventListener('click', this.click.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -53,11 +58,20 @@ class ExpandToggle {
 | 
			
		|||
 | 
			
		||||
    click(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        let matchingElems = document.querySelectorAll(this.selector);
 | 
			
		||||
        for (let i = 0, len = matchingElems.length; i < len; i++) {
 | 
			
		||||
            this.isOpen ?  this.close(matchingElems[i]) : this.open(matchingElems[i]);
 | 
			
		||||
 | 
			
		||||
        const matchingElems = document.querySelectorAll(this.selector);
 | 
			
		||||
        for (let match of matchingElems) {
 | 
			
		||||
            this.isOpen ?  this.close(match) : this.open(match);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isOpen = !this.isOpen;
 | 
			
		||||
        this.updateSystemAjax(this.isOpen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateSystemAjax(isOpen) {
 | 
			
		||||
        window.$http.patch(this.updateEndpoint, {
 | 
			
		||||
            expand: isOpen ? 'true' : 'false'
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
 | 
			
		||||
class HeaderMobileToggle {
 | 
			
		||||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
        this.toggleButton = elem.querySelector('.mobile-menu-toggle');
 | 
			
		||||
        this.menu = elem.querySelector('.header-links');
 | 
			
		||||
        this.open = false;
 | 
			
		||||
 | 
			
		||||
        this.toggleButton.addEventListener('click', this.onToggle.bind(this));
 | 
			
		||||
        this.onWindowClick = this.onWindowClick.bind(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onToggle(event) {
 | 
			
		||||
        this.open = !this.open;
 | 
			
		||||
        this.menu.classList.toggle('show', this.open);
 | 
			
		||||
        if (this.open) {
 | 
			
		||||
            window.addEventListener('click', this.onWindowClick)
 | 
			
		||||
        } else {
 | 
			
		||||
            window.removeEventListener('click', this.onWindowClick)
 | 
			
		||||
        }
 | 
			
		||||
        event.stopPropagation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onWindowClick(event) {
 | 
			
		||||
        this.onToggle(event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = HeaderMobileToggle;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,11 @@ import toggleSwitch from "./toggle-switch";
 | 
			
		|||
import pageDisplay from "./page-display";
 | 
			
		||||
import shelfSort from "./shelf-sort";
 | 
			
		||||
import homepageControl from "./homepage-control";
 | 
			
		||||
 | 
			
		||||
import headerMobileToggle from "./header-mobile-toggle";
 | 
			
		||||
import listSortControl from "./list-sort-control";
 | 
			
		||||
import triLayout from "./tri-layout";
 | 
			
		||||
import breadcrumbListing from "./breadcrumb-listing";
 | 
			
		||||
import permissionsTable from "./permissions-table";
 | 
			
		||||
 | 
			
		||||
const componentMapping = {
 | 
			
		||||
    'dropdown': dropdown,
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +45,11 @@ const componentMapping = {
 | 
			
		|||
    'page-display': pageDisplay,
 | 
			
		||||
    'shelf-sort': shelfSort,
 | 
			
		||||
    'homepage-control': homepageControl,
 | 
			
		||||
    'header-mobile-toggle': headerMobileToggle,
 | 
			
		||||
    'list-sort-control': listSortControl,
 | 
			
		||||
    'tri-layout': triLayout,
 | 
			
		||||
    'breadcrumb-listing': breadcrumbListing,
 | 
			
		||||
    'permissions-table': permissionsTable,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
window.components = {};
 | 
			
		||||
| 
						 | 
				
			
			@ -79,4 +88,4 @@ function initAll(parentElement) {
 | 
			
		|||
 | 
			
		||||
window.components.init = initAll;
 | 
			
		||||
 | 
			
		||||
export default initAll;
 | 
			
		||||
export default initAll;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
/**
 | 
			
		||||
 * ListSortControl
 | 
			
		||||
 * Manages the logic for the control which provides list sorting options.
 | 
			
		||||
 */
 | 
			
		||||
class ListSortControl {
 | 
			
		||||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
 | 
			
		||||
        this.sortInput = elem.querySelector('[name="sort"]');
 | 
			
		||||
        this.orderInput = elem.querySelector('[name="order"]');
 | 
			
		||||
        this.form = elem.querySelector('form');
 | 
			
		||||
 | 
			
		||||
        this.elem.addEventListener('click', event => {
 | 
			
		||||
            if (event.target.closest('[data-sort-value]') !== null) {
 | 
			
		||||
                this.sortOptionClick(event);
 | 
			
		||||
            }
 | 
			
		||||
            if (event.target.closest('[data-sort-dir]') !== null) {
 | 
			
		||||
                this.sortDirectionClick(event);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sortOptionClick(event) {
 | 
			
		||||
        const sortOption = event.target.closest('[data-sort-value]');
 | 
			
		||||
        this.sortInput.value = sortOption.getAttribute('data-sort-value');
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        this.form.submit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sortDirectionClick(event) {
 | 
			
		||||
        const currentDir = this.orderInput.value;
 | 
			
		||||
        const newDir = (currentDir === 'asc') ? 'desc' : 'asc';
 | 
			
		||||
        this.orderInput.value = newDir;
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        this.form.submit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ListSortControl;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +71,19 @@ class MarkdownEditor {
 | 
			
		|||
            if (action === 'insertDrawing') this.actionStartDrawing();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Mobile section toggling
 | 
			
		||||
        this.elem.addEventListener('click', event => {
 | 
			
		||||
            const toolbarLabel = event.target.closest('.editor-toolbar-label');
 | 
			
		||||
            if (!toolbarLabel) return;
 | 
			
		||||
 | 
			
		||||
            const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
 | 
			
		||||
            for (let activeElem of currentActiveSections) {
 | 
			
		||||
                activeElem.classList.remove('active');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        window.$events.listen('editor-markdown-update', value => {
 | 
			
		||||
            this.cm.setValue(value);
 | 
			
		||||
            this.updateAndRender();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ class Overlay {
 | 
			
		|||
        elem.addEventListener('click', event => {
 | 
			
		||||
             if (event.target === elem) return this.hide();
 | 
			
		||||
        });
 | 
			
		||||
        let closeButtons = elem.querySelectorAll('.overlay-close');
 | 
			
		||||
        let closeButtons = elem.querySelectorAll('.popup-header-close');
 | 
			
		||||
        for (let i=0; i < closeButtons.length; i++) {
 | 
			
		||||
            closeButtons[i].addEventListener('click', this.hide.bind(this));
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ class PageComments {
 | 
			
		|||
        commentElem.querySelector('[comment-edit-container]').style.display = 'block';
 | 
			
		||||
        let textArea = commentElem.querySelector('[comment-edit-container] textarea');
 | 
			
		||||
        let lineCount = textArea.value.split('\n').length;
 | 
			
		||||
        textArea.style.height = (lineCount * 20) + 'px';
 | 
			
		||||
        textArea.style.height = ((lineCount * 20) + 40) + 'px';
 | 
			
		||||
        this.editingComment = commentElem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +88,7 @@ class PageComments {
 | 
			
		|||
            commentElem.parentNode.removeChild(commentElem);
 | 
			
		||||
            window.$events.emit('success', window.trans('entities.comment_deleted_success'));
 | 
			
		||||
            this.updateCount();
 | 
			
		||||
            this.hideForm();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +130,7 @@ class PageComments {
 | 
			
		|||
    showForm() {
 | 
			
		||||
        this.formContainer.style.display = 'block';
 | 
			
		||||
        this.formContainer.parentNode.style.display = 'block';
 | 
			
		||||
        this.elem.querySelector('[comment-add-button]').style.display = 'none';
 | 
			
		||||
        this.elem.querySelector('[comment-add-button-container]').style.display = 'none';
 | 
			
		||||
        this.formInput.focus();
 | 
			
		||||
        window.scrollToElement(this.formInput);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +138,18 @@ class PageComments {
 | 
			
		|||
    hideForm() {
 | 
			
		||||
        this.formContainer.style.display = 'none';
 | 
			
		||||
        this.formContainer.parentNode.style.display = 'none';
 | 
			
		||||
        this.elem.querySelector('[comment-add-button]').style.display = 'block';
 | 
			
		||||
        const addButtonContainer = this.elem.querySelector('[comment-add-button-container]');
 | 
			
		||||
        if (this.getCommentCount() > 0) {
 | 
			
		||||
            this.elem.appendChild(addButtonContainer)
 | 
			
		||||
        } else {
 | 
			
		||||
            const countBar = this.elem.querySelector('[comment-count-bar]');
 | 
			
		||||
            countBar.appendChild(addButtonContainer);
 | 
			
		||||
        }
 | 
			
		||||
        addButtonContainer.style.display = 'block';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getCommentCount() {
 | 
			
		||||
        return this.elem.querySelectorAll('.comment-box[comment]').length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setReply(commentElem) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,8 +208,8 @@ class PageDisplay {
 | 
			
		|||
            let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
 | 
			
		||||
 | 
			
		||||
            // observe each heading
 | 
			
		||||
            for (let i = 0; i !== headings.length; ++i) {
 | 
			
		||||
                pageNavObserver.observe(headings[i]);
 | 
			
		||||
            for (let heading of headings) {
 | 
			
		||||
                pageNavObserver.observe(heading);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -221,14 +221,9 @@ class PageDisplay {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        function toggleAnchorHighlighting(elementId, shouldHighlight) {
 | 
			
		||||
            let anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
 | 
			
		||||
            for (let i = 0; i < anchorsToHighlight.length; i++) {
 | 
			
		||||
                // Change below to use classList.toggle when IE support is dropped.
 | 
			
		||||
                if (shouldHighlight) {
 | 
			
		||||
                    anchorsToHighlight[i].classList.add('current-heading');
 | 
			
		||||
                } else {
 | 
			
		||||
                    anchorsToHighlight[i].classList.remove('current-heading');
 | 
			
		||||
                }
 | 
			
		||||
            const anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
 | 
			
		||||
            for (let anchor of anchorsToHighlight) {
 | 
			
		||||
                anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
 | 
			
		||||
class PermissionsTable {
 | 
			
		||||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.container = elem;
 | 
			
		||||
 | 
			
		||||
        // Handle toggle all event
 | 
			
		||||
        const toggleAll = elem.querySelector('[permissions-table-toggle-all]');
 | 
			
		||||
        toggleAll.addEventListener('click', this.toggleAllClick.bind(this));
 | 
			
		||||
 | 
			
		||||
        // Handle toggle row event
 | 
			
		||||
        const toggleRowElems = elem.querySelectorAll('[permissions-table-toggle-all-in-row]');
 | 
			
		||||
        for (let toggleRowElem of toggleRowElems) {
 | 
			
		||||
            toggleRowElem.addEventListener('click', this.toggleRowClick.bind(this));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Handle toggle column event
 | 
			
		||||
        const toggleColumnElems = elem.querySelectorAll('[permissions-table-toggle-all-in-column]');
 | 
			
		||||
        for (let toggleColElem of toggleColumnElems) {
 | 
			
		||||
            toggleColElem.addEventListener('click', this.toggleColumnClick.bind(this));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleAllClick(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        this.toggleAllInElement(this.container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleRowClick(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        this.toggleAllInElement(event.target.closest('tr'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleColumnClick(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
        const tableCell = event.target.closest('th,td');
 | 
			
		||||
        const colIndex = Array.from(tableCell.parentElement.children).indexOf(tableCell);
 | 
			
		||||
        const tableRows = tableCell.closest('table').querySelectorAll('tr');
 | 
			
		||||
        const inputsToToggle = [];
 | 
			
		||||
 | 
			
		||||
        for (let row of tableRows) {
 | 
			
		||||
            const targetCell = row.children[colIndex];
 | 
			
		||||
            if (targetCell) {
 | 
			
		||||
                inputsToToggle.push(...targetCell.querySelectorAll('input[type=checkbox]'));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this.toggleAllInputs(inputsToToggle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleAllInElement(domElem) {
 | 
			
		||||
        const inputsToToggle = domElem.querySelectorAll('input[type=checkbox]');
 | 
			
		||||
        this.toggleAllInputs(inputsToToggle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleAllInputs(inputsToToggle) {
 | 
			
		||||
        const currentState = inputsToToggle.length > 0 ? inputsToToggle[0].checked : false;
 | 
			
		||||
        for (let checkbox of inputsToToggle) {
 | 
			
		||||
            checkbox.checked = !currentState;
 | 
			
		||||
            checkbox.dispatchEvent(new Event('change'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default PermissionsTable;
 | 
			
		||||
| 
						 | 
				
			
			@ -3,15 +3,15 @@ class ToggleSwitch {
 | 
			
		|||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
        this.input = elem.querySelector('input');
 | 
			
		||||
        this.input = elem.querySelector('input[type=hidden]');
 | 
			
		||||
        this.checkbox = elem.querySelector('input[type=checkbox]');
 | 
			
		||||
 | 
			
		||||
        this.elem.onclick = this.onClick.bind(this);
 | 
			
		||||
        this.checkbox.addEventListener('change', this.onClick.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onClick(event) {
 | 
			
		||||
        let checked = this.input.value !== 'true';
 | 
			
		||||
        let checked = this.checkbox.checked;
 | 
			
		||||
        this.input.value = checked ? 'true' : 'false';
 | 
			
		||||
        checked ? this.elem.classList.add('active') : this.elem.classList.remove('active');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
 | 
			
		||||
class TriLayout {
 | 
			
		||||
 | 
			
		||||
    constructor(elem) {
 | 
			
		||||
        this.elem = elem;
 | 
			
		||||
 | 
			
		||||
        this.lastLayoutType = 'none';
 | 
			
		||||
        this.onDestroy = null;
 | 
			
		||||
        this.scrollCache = {
 | 
			
		||||
            'content': 0,
 | 
			
		||||
            'info': 0,
 | 
			
		||||
        };
 | 
			
		||||
        this.lastTabShown = 'content';
 | 
			
		||||
 | 
			
		||||
        // Bind any listeners
 | 
			
		||||
        this.mobileTabClick = this.mobileTabClick.bind(this);
 | 
			
		||||
 | 
			
		||||
        // Watch layout changes
 | 
			
		||||
        this.updateLayout();
 | 
			
		||||
        window.addEventListener('resize', event => {
 | 
			
		||||
            this.updateLayout();
 | 
			
		||||
        }, {passive: true});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateLayout() {
 | 
			
		||||
        let newLayout = 'tablet';
 | 
			
		||||
        if (window.innerWidth <= 1000) newLayout =  'mobile';
 | 
			
		||||
        if (window.innerWidth >= 1400) newLayout =  'desktop';
 | 
			
		||||
        if (newLayout === this.lastLayoutType) return;
 | 
			
		||||
 | 
			
		||||
        if (this.onDestroy) {
 | 
			
		||||
            this.onDestroy();
 | 
			
		||||
            this.onDestroy = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (newLayout === 'desktop') {
 | 
			
		||||
            this.setupDesktop();
 | 
			
		||||
        } else if (newLayout === 'mobile') {
 | 
			
		||||
            this.setupMobile();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.lastLayoutType = newLayout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setupMobile() {
 | 
			
		||||
        const layoutTabs = document.querySelectorAll('[tri-layout-mobile-tab]');
 | 
			
		||||
        for (let tab of layoutTabs) {
 | 
			
		||||
            tab.addEventListener('click', this.mobileTabClick);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.onDestroy = () => {
 | 
			
		||||
            for (let tab of layoutTabs) {
 | 
			
		||||
                tab.removeEventListener('click', this.mobileTabClick);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setupDesktop() {
 | 
			
		||||
        //
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Action to run when the mobile info toggle bar is clicked/tapped
 | 
			
		||||
     * @param event
 | 
			
		||||
     */
 | 
			
		||||
    mobileTabClick(event) {
 | 
			
		||||
        const tab = event.target.getAttribute('tri-layout-mobile-tab');
 | 
			
		||||
        this.scrollCache[this.lastTabShown] = document.documentElement.scrollTop;
 | 
			
		||||
 | 
			
		||||
        // Set tab status
 | 
			
		||||
        const activeTabs = document.querySelectorAll('.tri-layout-mobile-tab.active');
 | 
			
		||||
        for (let tab of activeTabs) {
 | 
			
		||||
            tab.classList.remove('active');
 | 
			
		||||
        }
 | 
			
		||||
        event.target.classList.add('active');
 | 
			
		||||
 | 
			
		||||
        // Toggle section
 | 
			
		||||
        const showInfo = (tab === 'info');
 | 
			
		||||
        this.elem.classList.toggle('show-info', showInfo);
 | 
			
		||||
 | 
			
		||||
        // Set the scroll position from cache
 | 
			
		||||
        const pageHeader = document.querySelector('header');
 | 
			
		||||
        const defaultScrollTop = pageHeader.getBoundingClientRect().bottom;
 | 
			
		||||
        document.documentElement.scrollTop = this.scrollCache[tab] || defaultScrollTop;
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
            document.documentElement.scrollTop = this.scrollCache[tab] || defaultScrollTop;
 | 
			
		||||
        }, 50);
 | 
			
		||||
 | 
			
		||||
        this.lastTabShown = tab;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default TriLayout;
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +432,7 @@ class WysiwygEditor {
 | 
			
		|||
            plugins: this.plugins,
 | 
			
		||||
            imagetools_toolbar: 'imageoptions',
 | 
			
		||||
            toolbar: this.getToolBar(),
 | 
			
		||||
            content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
 | 
			
		||||
            content_style: "html, body {background: #FFF;} body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
 | 
			
		||||
            style_formats: [
 | 
			
		||||
                {title: "Header Large", format: "h2"},
 | 
			
		||||
                {title: "Header Medium", format: "h3"},
 | 
			
		||||
| 
						 | 
				
			
			@ -517,6 +517,16 @@ class WysiwygEditor {
 | 
			
		|||
                    if (scrollId) {
 | 
			
		||||
                        scrollToText(scrollId);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Override for touch events to allow scroll on mobile
 | 
			
		||||
                    const container = editor.getContainer();
 | 
			
		||||
                    const toolbarButtons = container.querySelectorAll('.mce-btn');
 | 
			
		||||
                    for (let button of toolbarButtons) {
 | 
			
		||||
                        button.addEventListener('touchstart', event => {
 | 
			
		||||
                            event.stopPropagation();
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    window.editor = editor;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                function editorChange() {
 | 
			
		||||
| 
						 | 
				
			
			@ -600,6 +610,7 @@ class WysiwygEditor {
 | 
			
		|||
 | 
			
		||||
                // Paste image-uploads
 | 
			
		||||
                editor.on('paste', event => editorPaste(event, editor, context));
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,26 +36,6 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.anim.menuIn {
 | 
			
		||||
  transform-origin: 100% 0%;
 | 
			
		||||
  animation-name: menuIn;
 | 
			
		||||
  animation-duration: 120ms;
 | 
			
		||||
  animation-delay: 0s;
 | 
			
		||||
  animation-timing-function: cubic-bezier(.62, .28, .23, .99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes menuIn {
 | 
			
		||||
  from {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: scale3d(0, 0, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  to {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    transform: scale3d(1, 1, 1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes loadingBob {
 | 
			
		||||
  0% {
 | 
			
		||||
    transform: translate3d(0, 0, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +69,4 @@
 | 
			
		|||
  animation-duration: 180ms;
 | 
			
		||||
  animation-delay: 0s;
 | 
			
		||||
  animation-timing-function: cubic-bezier(.62, .28, .23, .99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.selectFade {
 | 
			
		||||
  transition: background-color ease-in-out 3000ms;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,136 +1,7 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
* This file container all block styling including background shading,
 | 
			
		||||
* margins, paddings & borders.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* Background Shading
 | 
			
		||||
*/
 | 
			
		||||
.shaded {
 | 
			
		||||
  background-color: #f1f1f1;
 | 
			
		||||
  &.pos {
 | 
			
		||||
    background-color: lighten($positive, 40%);
 | 
			
		||||
  }
 | 
			
		||||
  &.neg {
 | 
			
		||||
    background-color: lighten($negative, 20%);
 | 
			
		||||
  }
 | 
			
		||||
  &.primary {
 | 
			
		||||
    background-color: lighten($primary, 40%);
 | 
			
		||||
  }
 | 
			
		||||
  &.secondary {
 | 
			
		||||
    background-color: lighten($secondary, 30%);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* Bordering
 | 
			
		||||
*/
 | 
			
		||||
.bordered {
 | 
			
		||||
  border: 1px solid #BBB;
 | 
			
		||||
  &.pos {
 | 
			
		||||
    border-color: $positive;
 | 
			
		||||
  }
 | 
			
		||||
  &.neg {
 | 
			
		||||
    border-color: $negative;
 | 
			
		||||
  }
 | 
			
		||||
  &.primary {
 | 
			
		||||
    border-color: $primary;
 | 
			
		||||
  }
 | 
			
		||||
  &.secondary {
 | 
			
		||||
    border-color: $secondary;
 | 
			
		||||
  }
 | 
			
		||||
  &.thick {
 | 
			
		||||
    border-width: 2px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.rounded {
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* Padding
 | 
			
		||||
*/
 | 
			
		||||
.nopadding {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
.padded {
 | 
			
		||||
  padding: $-l;
 | 
			
		||||
  &.large {
 | 
			
		||||
    padding: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
  >h1, >h2, >h3, >h4 {
 | 
			
		||||
    &:first-child {
 | 
			
		||||
      margin-top: 0.1em;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.padded-vertical, .padded-top {
 | 
			
		||||
  padding-top: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    padding-top: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.padded-vertical, .padded-bottom {
 | 
			
		||||
  padding-bottom: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    padding-bottom: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.padded-horizontal, .padded-left {
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    padding-left: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.padded-horizontal, .padded-right {
 | 
			
		||||
  padding-right: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    padding-right: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* Margins
 | 
			
		||||
*/
 | 
			
		||||
.margins {
 | 
			
		||||
  margin: $-l;
 | 
			
		||||
  &.large {
 | 
			
		||||
    margin: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.margins-vertical, .margin-top {
 | 
			
		||||
  margin-top: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    margin-top: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.margins-vertical, .margin-bottom {
 | 
			
		||||
  margin-bottom: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    margin-bottom: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.margins-horizontal, .margin-left {
 | 
			
		||||
  margin-left: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    margin-left: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.margins-horizontal, .margin-right {
 | 
			
		||||
  margin-right: $-m;
 | 
			
		||||
  &.large {
 | 
			
		||||
    margin-right: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callouts
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.callout {
 | 
			
		||||
  border-left: 3px solid #BBB;
 | 
			
		||||
  background-color: #EEE;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,19 +53,22 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Card-style blocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.card {
 | 
			
		||||
  margin: $-m;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.2);
 | 
			
		||||
  box-shadow: $bs-card;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  border: 1px solid transparent;
 | 
			
		||||
  h3 {
 | 
			
		||||
    padding: $-m;
 | 
			
		||||
    border-bottom: 1px solid #E8E8E8;
 | 
			
		||||
    padding: $-m $-m $-xs;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    font-size: $fs-s;
 | 
			
		||||
    color: #888;
 | 
			
		||||
    fill: #888;
 | 
			
		||||
    font-size: $fs-m;
 | 
			
		||||
    color: #222;
 | 
			
		||||
    fill: #222;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
  }
 | 
			
		||||
  h3 a {
 | 
			
		||||
    line-height: 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -208,18 +82,11 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .card {
 | 
			
		||||
  h3, .body, .empty-text {
 | 
			
		||||
    padding: $-s $-m;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card.drag-card {
 | 
			
		||||
  border: 1px solid #DDD;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  padding-left: $-s + 28px;
 | 
			
		||||
  padding: 0 0 0 ($-s + 28px);
 | 
			
		||||
  margin: $-s 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  .drag-card-action {
 | 
			
		||||
| 
						 | 
				
			
			@ -227,14 +94,12 @@
 | 
			
		|||
  }
 | 
			
		||||
  .handle, .drag-card-action {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    width: 28px;
 | 
			
		||||
    flex-grow: 0;
 | 
			
		||||
    padding-left: $-xs;
 | 
			
		||||
    padding-right: $-xs;
 | 
			
		||||
    padding: 0 $-xs;
 | 
			
		||||
    &:hover {
 | 
			
		||||
      background-color: #EEE;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -246,9 +111,6 @@
 | 
			
		|||
    margin: $-s 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  > div.padded {
 | 
			
		||||
    padding: $-s 0 !important;
 | 
			
		||||
  }
 | 
			
		||||
  .handle {
 | 
			
		||||
    background-color: #EEE;
 | 
			
		||||
    left: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -263,12 +125,89 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.well {
 | 
			
		||||
  background-color: #F8F8F8;
 | 
			
		||||
  padding: $-m;
 | 
			
		||||
  border: 1px solid #DDD;
 | 
			
		||||
.grid-card {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  border: 1px solid #ddd;
 | 
			
		||||
  margin-bottom: $-l;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  min-width: 100px;
 | 
			
		||||
  color: $text-dark;
 | 
			
		||||
  transition: border-color ease-in-out 120ms, box-shadow ease-in-out 120ms;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $text-dark;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    box-shadow: $bs-card;
 | 
			
		||||
  }
 | 
			
		||||
  h2 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    font-size: 1.5em;
 | 
			
		||||
    margin: 0 0 10px;
 | 
			
		||||
  }
 | 
			
		||||
  p {
 | 
			
		||||
    font-size: .7rem;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    line-height: 1.6em;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    border-top: 0;
 | 
			
		||||
    border-bottom-width: 2px;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content, .grid-card-footer {
 | 
			
		||||
    padding: $-l;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content + .grid-card-footer {
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bookshelf-grid-item .grid-card-content h2 a  {
 | 
			
		||||
  color: $color-bookshelf;
 | 
			
		||||
  fill: $color-bookshelf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.book-grid-item .grid-card-footer {
 | 
			
		||||
  p.small {
 | 
			
		||||
    font-size: .8em;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content-wrap.card {
 | 
			
		||||
  padding: $-m $-xxl;
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
  margin-bottom: $-xl;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  min-height: 60vh;
 | 
			
		||||
  &.auto-height {
 | 
			
		||||
    min-height: 0;
 | 
			
		||||
  }
 | 
			
		||||
  &.fill-width {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include smaller-than($xxl) {
 | 
			
		||||
  .content-wrap.card {
 | 
			
		||||
    padding: $-l $-xl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .content-wrap.card {
 | 
			
		||||
    padding: $-m $-l;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include smaller-than($s) {
 | 
			
		||||
  .content-wrap.card {
 | 
			
		||||
    padding: $-m $-s;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tags
 | 
			
		||||
 */
 | 
			
		||||
.tag-item {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  margin-bottom: $-xs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,14 @@
 | 
			
		|||
button {
 | 
			
		||||
  font-size: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin generate-button-colors($textColor, $backgroundColor) {
 | 
			
		||||
  background-color: $backgroundColor;
 | 
			
		||||
  color: $textColor;
 | 
			
		||||
  fill: $textColor;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  border: 1px solid $backgroundColor;
 | 
			
		||||
  vertical-align: top;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background-color: lighten($backgroundColor, 8%);
 | 
			
		||||
    //box-shadow: $bs-med;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    color: $textColor;
 | 
			
		||||
  }
 | 
			
		||||
  &:active {
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +17,6 @@
 | 
			
		|||
  &:focus {
 | 
			
		||||
    background-color: lighten($backgroundColor, 4%);
 | 
			
		||||
    box-shadow: $bs-light;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    color: $textColor;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,42 +24,36 @@
 | 
			
		|||
// Button Specific Variables
 | 
			
		||||
$button-border-radius: 2px;
 | 
			
		||||
 | 
			
		||||
.button-base {
 | 
			
		||||
.button  {
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  font-size: $fs-m;
 | 
			
		||||
  font-size: 0.85rem;
 | 
			
		||||
  line-height: 1.4em;
 | 
			
		||||
  padding: $-xs*1.3 $-m;
 | 
			
		||||
  margin: $-xs $-xs $-xs 0;
 | 
			
		||||
  margin-top: $-xs;
 | 
			
		||||
  margin-bottom: $-xs;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  border: none;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  outline: 0;
 | 
			
		||||
  border-radius: $button-border-radius;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  transition: all ease-in-out 120ms;
 | 
			
		||||
  box-shadow: 0;
 | 
			
		||||
  @include generate-button-colors(#EEE, $primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button, input[type="button"], input[type="submit"]  {
 | 
			
		||||
  @extend .button-base;
 | 
			
		||||
  &.pos {
 | 
			
		||||
    @include generate-button-colors(#EEE, $positive);
 | 
			
		||||
  transition: background-color ease-in-out 120ms, box-shadow ease-in-out 120ms;
 | 
			
		||||
  box-shadow: none;
 | 
			
		||||
  background-color: $primary;
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  fill: #FFF;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  border: 1px solid $primary;
 | 
			
		||||
  vertical-align: top;
 | 
			
		||||
  &:hover, &:focus {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
  }
 | 
			
		||||
  &.neg {
 | 
			
		||||
    @include generate-button-colors(#EEE, $negative);
 | 
			
		||||
  }
 | 
			
		||||
  &.secondary {
 | 
			
		||||
    @include generate-button-colors(#EEE, $secondary);
 | 
			
		||||
  }
 | 
			
		||||
  &.muted {
 | 
			
		||||
    @include generate-button-colors(#EEE, #AAA);
 | 
			
		||||
  }
 | 
			
		||||
  &.muted-light {
 | 
			
		||||
    @include generate-button-colors(#666, #e4e4e4);
 | 
			
		||||
  &:active {
 | 
			
		||||
    background-color: darken($primary, 8%);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button.primary {
 | 
			
		||||
  @include generate-button-colors(#FFFFFF, $primary);
 | 
			
		||||
}
 | 
			
		||||
.button.outline {
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  color: #888;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,78 +63,38 @@ $button-border-radius: 2px;
 | 
			
		|||
    box-shadow: none;
 | 
			
		||||
    background-color: #EEE;
 | 
			
		||||
  }
 | 
			
		||||
  &.page {
 | 
			
		||||
    border-color: $color-page;
 | 
			
		||||
    color: $color-page;
 | 
			
		||||
    fill: $color-page;
 | 
			
		||||
    &:hover, &:focus, &:active {
 | 
			
		||||
      background-color: $color-page;
 | 
			
		||||
      color: #FFF;
 | 
			
		||||
      fill: #FFF;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &.chapter {
 | 
			
		||||
    border-color: $color-chapter;
 | 
			
		||||
    color: $color-chapter;
 | 
			
		||||
    fill: $color-chapter;
 | 
			
		||||
    &:hover, &:focus, &:active {
 | 
			
		||||
      background-color: $color-chapter;
 | 
			
		||||
      color: #FFF;
 | 
			
		||||
      fill: #FFF;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &.book {
 | 
			
		||||
    border-color: $color-book;
 | 
			
		||||
    color: $color-book;
 | 
			
		||||
    fill: $color-book;
 | 
			
		||||
    &:hover, &:focus, &:active {
 | 
			
		||||
      background-color: $color-book;
 | 
			
		||||
      color: #FFF;
 | 
			
		||||
      fill: #FFF;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button + .button {
 | 
			
		||||
  margin-left: $-s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button.small {
 | 
			
		||||
  font-size: 0.75rem;
 | 
			
		||||
  padding: $-xs*1.2 $-s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-button {
 | 
			
		||||
  @extend .link;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  border: none;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  font-size: 0.75rem;
 | 
			
		||||
  line-height: 1.4em;
 | 
			
		||||
  &:focus, &:active {
 | 
			
		||||
    outline: 0;
 | 
			
		||||
  }
 | 
			
		||||
  &:hover {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
  }
 | 
			
		||||
  &.neg {
 | 
			
		||||
    color: $negative;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-group {
 | 
			
		||||
  @include clearfix;
 | 
			
		||||
  .button, button[type="button"] {
 | 
			
		||||
    margin: $-xs 0 $-xs 0;
 | 
			
		||||
    float: left;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
    &:first-child {
 | 
			
		||||
      border-radius: $button-border-radius 0 0 $button-border-radius;
 | 
			
		||||
    }
 | 
			
		||||
    &:last-child {
 | 
			
		||||
      border-radius: 0 $button-border-radius $button-border-radius 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button.block {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  display: block;
 | 
			
		||||
  &.text-left {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button.icon {
 | 
			
		||||
| 
						 | 
				
			
			@ -160,9 +112,7 @@ $button-border-radius: 2px;
 | 
			
		|||
    width: 24px;
 | 
			
		||||
    height: 24px;
 | 
			
		||||
  }
 | 
			
		||||
  padding: $-s $-m;
 | 
			
		||||
  padding-bottom: $-s - 2px;
 | 
			
		||||
  padding-left: $-m*2 + 24px;
 | 
			
		||||
  padding: $-s $-m ($-s - 2px) ($-m*2 + 24px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button[disabled] {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * Status text colors
 | 
			
		||||
 */
 | 
			
		||||
.text-pos, .text-pos:hover, .text-pos-hover:hover {
 | 
			
		||||
  color: $positive !important;
 | 
			
		||||
  fill: $positive !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-warn, .text-warn:hover, .text-warn-hover:hover {
 | 
			
		||||
  color: $warning !important;
 | 
			
		||||
  fill: $warning !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-neg, .text-neg:hover, .text-neg-hover:hover  {
 | 
			
		||||
  color: $negative !important;
 | 
			
		||||
  fill: $negative !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Style text colors
 | 
			
		||||
 */
 | 
			
		||||
.text-primary, .text-primary:hover, .text-primary-hover:hover  {
 | 
			
		||||
  color: $primary !important;
 | 
			
		||||
  fill: $primary !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-muted {
 | 
			
		||||
  color: lighten($text-dark, 26%) !important;
 | 
			
		||||
  fill: lighten($text-dark, 26%) !important;
 | 
			
		||||
  &.small, .small {
 | 
			
		||||
    color: lighten($text-dark, 32%) !important;
 | 
			
		||||
    fill: lighten($text-dark, 32%) !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Entity text colors
 | 
			
		||||
 */
 | 
			
		||||
.text-bookshelf, .text-bookshelf:hover {
 | 
			
		||||
  color: $color-bookshelf;
 | 
			
		||||
  fill: $color-bookshelf;
 | 
			
		||||
}
 | 
			
		||||
.text-book, .text-book:hover {
 | 
			
		||||
  color: $color-book;
 | 
			
		||||
  fill: $color-book;
 | 
			
		||||
}
 | 
			
		||||
.text-page, .text-page:hover {
 | 
			
		||||
  color: $color-page;
 | 
			
		||||
  fill: $color-page;
 | 
			
		||||
}
 | 
			
		||||
.text-page.draft, .text-page.draft:hover {
 | 
			
		||||
  color: $color-page-draft;
 | 
			
		||||
  fill: $color-page-draft;
 | 
			
		||||
}
 | 
			
		||||
.text-chapter, .text-chapter:hover {
 | 
			
		||||
  color: $color-chapter;
 | 
			
		||||
  fill: $color-chapter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Entity background colors
 | 
			
		||||
 */
 | 
			
		||||
.bg-book {
 | 
			
		||||
  background-color: $color-book;
 | 
			
		||||
}
 | 
			
		||||
.bg-chapter {
 | 
			
		||||
  background-color: $color-chapter;
 | 
			
		||||
}
 | 
			
		||||
.bg-shelf {
 | 
			
		||||
  background-color: $color-bookshelf;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -54,13 +54,18 @@
 | 
			
		|||
  transition: all ease-in-out 180ms;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  svg[data-icon="caret-right"] {
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
    font-size: 1rem;
 | 
			
		||||
    transition: all ease-in-out 180ms;
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
    transform-origin: 25% 50%;
 | 
			
		||||
    transform-origin: 50% 50%;
 | 
			
		||||
  }
 | 
			
		||||
  &.open svg[data-icon="caret-right"] {
 | 
			
		||||
    transform: rotate(90deg);
 | 
			
		||||
  }
 | 
			
		||||
  svg[data-icon="caret-right"] + * {
 | 
			
		||||
    margin-left: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[overlay] {
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +115,7 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.corner-button {
 | 
			
		||||
.popup-footer button, .popup-header-close {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +123,16 @@
 | 
			
		|||
  height: 40px;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  box-shadow: none;
 | 
			
		||||
  &:active {
 | 
			
		||||
    outline: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.popup-header-close {
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  border: 0;
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  padding: 0 $-m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-header, .popup-footer {
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +145,9 @@
 | 
			
		|||
    padding: 8px $-m;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.popup-footer {
 | 
			
		||||
  margin-top: 1px;
 | 
			
		||||
}
 | 
			
		||||
body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
			
		||||
  height: 444px;
 | 
			
		||||
  min-height: 444px;
 | 
			
		||||
| 
						 | 
				
			
			@ -137,6 +155,9 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
			
		|||
#entity-selector-wrap .popup-body .form-group {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
.popup-body .entity-selector-container {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.image-manager-body {
 | 
			
		||||
  min-height: 70vh;
 | 
			
		||||
| 
						 | 
				
			
			@ -583,27 +604,26 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.comment-box {
 | 
			
		||||
  clear: left;
 | 
			
		||||
  border: 1px solid #DDD;
 | 
			
		||||
  margin-bottom: $-s;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  .content {
 | 
			
		||||
    padding: $-s;
 | 
			
		||||
    font-size: 0.666em;
 | 
			
		||||
    p, ul, ol {
 | 
			
		||||
      font-size: $fs-m;
 | 
			
		||||
      margin: .5em 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .reply-row {
 | 
			
		||||
    padding: $-xs $-s;
 | 
			
		||||
  .actions {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transition: opacity ease-in-out 120ms;
 | 
			
		||||
  }
 | 
			
		||||
  &:hover .actions {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-box .header {
 | 
			
		||||
  padding: $-xs $-s;
 | 
			
		||||
  background-color: #f8f8f8;
 | 
			
		||||
  border-bottom: 1px solid #DDD;
 | 
			
		||||
  .meta {
 | 
			
		||||
    img, a, span {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
| 
						 | 
				
			
			@ -626,4 +646,11 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
			
		|||
 | 
			
		||||
#tag-manager .drag-card {
 | 
			
		||||
  max-width: 500px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.permissions-table [permissions-table-toggle-all-in-row] {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.permissions-table tr:hover [permissions-table-toggle-all-in-row] {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +63,34 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  #markdown-editor {
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
  }
 | 
			
		||||
  #markdown-editor .markdown-editor-wrap {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  #markdown-editor .editor-toolbar {
 | 
			
		||||
    padding: 0;
 | 
			
		||||
  }
 | 
			
		||||
  #markdown-editor .editor-toolbar > * {
 | 
			
		||||
    padding: $-xs $-s;
 | 
			
		||||
  }
 | 
			
		||||
  .editor-toolbar-label {
 | 
			
		||||
    float: none !important;
 | 
			
		||||
    border-bottom: 1px solid #DDD;
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  .markdown-editor-wrap:not(.active) .editor-toolbar + div, .markdown-editor-wrap:not(.active) .editor-toolbar .buttons {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  #markdown-editor .markdown-editor-wrap:not(.active) {
 | 
			
		||||
    flex-grow: 0;
 | 
			
		||||
    flex: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.markdown-display {
 | 
			
		||||
  padding: 0 $-m 0;
 | 
			
		||||
  margin-left: -1px;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +126,7 @@ label {
 | 
			
		|||
  line-height: 1.4em;
 | 
			
		||||
  font-size: 0.94em;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  color: #666;
 | 
			
		||||
  padding-bottom: 2px;
 | 
			
		||||
  margin-bottom: 0.2em;
 | 
			
		||||
  &.inline {
 | 
			
		||||
| 
						 | 
				
			
			@ -139,56 +167,77 @@ input[type=date] {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.toggle-switch {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  background-color: #BBB;
 | 
			
		||||
  width: 36px;
 | 
			
		||||
  height: 14px;
 | 
			
		||||
  border-radius: 7px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  transition: all ease-in-out 120ms;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  &:after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    margin-top: -3px;
 | 
			
		||||
    width: 20px;
 | 
			
		||||
    height: 20px;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    background-color: #fafafa;
 | 
			
		||||
    border: 1px solid #CCC;
 | 
			
		||||
    box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
 | 
			
		||||
    transition: all ease-in-out 120ms;
 | 
			
		||||
  }
 | 
			
		||||
  &.active {
 | 
			
		||||
    background-color: rgba($positive, 0.4);
 | 
			
		||||
    &:after {
 | 
			
		||||
      left: 16px;
 | 
			
		||||
      background-color: $positive;
 | 
			
		||||
      border: darken($positive, 20%);
 | 
			
		||||
  display: inline-grid;
 | 
			
		||||
  grid-template-columns: (16px + $-s) 1fr;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin: $-m 0;
 | 
			
		||||
  .custom-checkbox {
 | 
			
		||||
    width: 16px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    border: 2px solid currentColor;
 | 
			
		||||
    opacity: 0.6;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    fill: currentColor;
 | 
			
		||||
    .svg-icon {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      bottom: auto;
 | 
			
		||||
      top: -1.5px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      transition: transform ease-in-out 120ms;
 | 
			
		||||
      transform: scale(0);
 | 
			
		||||
      transform-origin: center center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  input[type=checkbox] {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  input[type=checkbox]:checked + .custom-checkbox .svg-icon {
 | 
			
		||||
    transform: scale(1);
 | 
			
		||||
  }
 | 
			
		||||
  .custom-checkbox:hover {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
    opacity: 0.8;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.toggle-switch-checkbox {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
input:checked + .toggle-switch {
 | 
			
		||||
  background-color: rgba($positive, 0.4);
 | 
			
		||||
  &:after {
 | 
			
		||||
    left: 16px;
 | 
			
		||||
    background-color: $positive;
 | 
			
		||||
    border: darken($positive, 20%);
 | 
			
		||||
.toggle-switch-list {
 | 
			
		||||
  .toggle-switch {
 | 
			
		||||
    margin: $-xs 0;
 | 
			
		||||
  }
 | 
			
		||||
  &.compact .toggle-switch {
 | 
			
		||||
    margin: 1px 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group {
 | 
			
		||||
  margin-bottom: $-s;
 | 
			
		||||
  textarea {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setting-list > div {
 | 
			
		||||
  border-bottom: 1px solid #DDD;
 | 
			
		||||
  padding: $-xl 0;
 | 
			
		||||
  &:last-child {
 | 
			
		||||
    border-bottom: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.setting-list-label {
 | 
			
		||||
  color: #222;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
.setting-list-label + p.small {
 | 
			
		||||
  margin-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
.setting-list-label + .grid {
 | 
			
		||||
  margin-top: $-m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setting-list .grid, .stretch-inputs {
 | 
			
		||||
  input[type=text], input[type=email], input[type=password], select {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    min-height: 64px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +246,8 @@ input:checked + .toggle-switch {
 | 
			
		|||
  font-family: monospace;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
  min-height: 100px;
 | 
			
		||||
  display: block;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group {
 | 
			
		||||
| 
						 | 
				
			
			@ -206,11 +257,9 @@ input:checked + .toggle-switch {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.form-group[collapsible] {
 | 
			
		||||
  margin-left: -$-m;
 | 
			
		||||
  margin-right: -$-m;
 | 
			
		||||
  padding: 0 $-m;
 | 
			
		||||
  border-top: 1px solid #DDD;
 | 
			
		||||
  border-bottom: 1px solid #DDD;
 | 
			
		||||
  border: 1px solid #DDD;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  .collapse-title {
 | 
			
		||||
    margin-left: -$-m;
 | 
			
		||||
    margin-right: -$-m;
 | 
			
		||||
| 
						 | 
				
			
			@ -238,9 +287,6 @@ input:checked + .toggle-switch {
 | 
			
		|||
  &.open .collapse-title label:before {
 | 
			
		||||
    transform: rotate(90deg);
 | 
			
		||||
  }
 | 
			
		||||
  &+.form-group[collapsible] {
 | 
			
		||||
    margin-top: -($-s + 1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inline-input-style {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,6 +350,13 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
 | 
			
		|||
    width: 300px;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  &.flexible input {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .search-box-cancel {
 | 
			
		||||
    left: auto;
 | 
			
		||||
    right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.outline > input {
 | 
			
		||||
| 
						 | 
				
			
			@ -317,13 +370,6 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#login-form label[for="remember"] {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
#login-form label.toggle-switch {
 | 
			
		||||
  margin-left: $-xl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.image-picker img {
 | 
			
		||||
  background-color: #BBB;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,930 +0,0 @@
 | 
			
		|||
 | 
			
		||||
/** Flexbox styling rules **/
 | 
			
		||||
body.flexbox {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  #content {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    min-height: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-fill {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  min-height: 0;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  &.rows {
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
  }
 | 
			
		||||
  &.columns {
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  min-height: 0;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex.scroll {
 | 
			
		||||
  //overflow-y: auto;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  &.sidebar {
 | 
			
		||||
    margin-right: -14px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.flex.scroll .scroll-body {
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-child > div {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex.sidebar {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  background-color: #F2F2F2;
 | 
			
		||||
  max-width: 360px;
 | 
			
		||||
  min-height: 90vh;
 | 
			
		||||
  section {
 | 
			
		||||
    margin: $-m;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.flex.sidebar + .flex.content {
 | 
			
		||||
  flex: 3;
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
  padding: 0 $-l;
 | 
			
		||||
  border-left: 1px solid #DDD;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.flex.sidebar .sidebar-toggle {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($xl) {
 | 
			
		||||
  body.sidebar-layout {
 | 
			
		||||
    padding-left: 30px;
 | 
			
		||||
  }
 | 
			
		||||
  .flex.sidebar {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    z-index: 100;
 | 
			
		||||
    padding-right: 30px;
 | 
			
		||||
    width: 360px;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    transform: translate3d(-330px, 0, 0);
 | 
			
		||||
    transition: transform ease-in-out 120ms;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
  }
 | 
			
		||||
  .flex.sidebar.open {
 | 
			
		||||
    box-shadow: 1px 2px 2px 1px rgba(0,0,0,.10);
 | 
			
		||||
    transform: translate3d(0, 0, 0);
 | 
			
		||||
    .sidebar-toggle i {
 | 
			
		||||
      transform: rotate(180deg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .flex.sidebar .sidebar-toggle {
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    opacity: 0.9;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    width: 30px;
 | 
			
		||||
    fill: #666;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    border: 1px solid #DDD;
 | 
			
		||||
    border-top: 1px solid #BBB;
 | 
			
		||||
    padding-top: $-m;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    svg {
 | 
			
		||||
      opacity: 0.5;
 | 
			
		||||
      transition: all ease-in-out 120ms;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
    }
 | 
			
		||||
    &:hover i {
 | 
			
		||||
      opacity: 1;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .sidebar .scroll-body {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
  }
 | 
			
		||||
  #sidebar .scroll-body.fixed {
 | 
			
		||||
    width: auto !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include larger-than($xl) {
 | 
			
		||||
  #sidebar .scroll-body.fixed {
 | 
			
		||||
    z-index: 5;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    padding-right: $-m;
 | 
			
		||||
    width: 30%;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
    -ms-overflow-style: none;
 | 
			
		||||
    //background-color: $primary-faded;
 | 
			
		||||
    border-left: 1px solid #DDD;
 | 
			
		||||
    &::-webkit-scrollbar { width: 0 !important }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** Rules for all columns */
 | 
			
		||||
div[class^="col-"] img {
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container {
 | 
			
		||||
  max-width: $max-width;
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  padding-right: $-m;
 | 
			
		||||
  &.fluid {
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  &.medium {
 | 
			
		||||
    max-width: 992px;
 | 
			
		||||
  }
 | 
			
		||||
  &.small {
 | 
			
		||||
    max-width: 840px;
 | 
			
		||||
  }
 | 
			
		||||
  &.nopad {
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.row {
 | 
			
		||||
  margin-left: -$-m;
 | 
			
		||||
  margin-right: -$-m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-column-gap: $-l;
 | 
			
		||||
  grid-row-gap: $-l;
 | 
			
		||||
  &.third {
 | 
			
		||||
    grid-template-columns: 1fr 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-card {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  border: 1px solid #ddd;
 | 
			
		||||
  min-width: 100px;
 | 
			
		||||
  h2 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    font-size: 1.5em;
 | 
			
		||||
    margin: 0 0 10px;
 | 
			
		||||
  }
 | 
			
		||||
  h2 a {
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    line-height: 1.2;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
  }
 | 
			
		||||
  p {
 | 
			
		||||
    font-size: .85em;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    line-height: 1.6em;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    border-top: 0;
 | 
			
		||||
    border-bottom-width: 2px;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content, .grid-card-footer {
 | 
			
		||||
    padding: $-l;
 | 
			
		||||
  }
 | 
			
		||||
  .grid-card-content + .grid-card-footer {
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.book-grid-item .grid-card-content h2 a  {
 | 
			
		||||
    color: $color-book;
 | 
			
		||||
    fill: $color-book;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bookshelf-grid-item .grid-card-content h2 a  {
 | 
			
		||||
  color: $color-bookshelf;
 | 
			
		||||
  fill: $color-bookshelf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.book-grid-item .grid-card-footer {
 | 
			
		||||
  p.small {
 | 
			
		||||
    font-size: .8em;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .grid.third {
 | 
			
		||||
    grid-template-columns: 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($s) {
 | 
			
		||||
  .grid.third {
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.float {
 | 
			
		||||
  float: left;
 | 
			
		||||
  &.right {
 | 
			
		||||
    float: right;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.block {
 | 
			
		||||
  display: block;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inline {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.block.inline {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  min-height: 1px;
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  padding-right: $-m;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
 | 
			
		||||
  float: left;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-12 {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-11 {
 | 
			
		||||
  width: 91.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-10 {
 | 
			
		||||
  width: 83.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-9 {
 | 
			
		||||
  width: 75%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-8 {
 | 
			
		||||
  width: 66.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-7 {
 | 
			
		||||
  width: 58.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-6 {
 | 
			
		||||
  width: 50%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-5 {
 | 
			
		||||
  width: 41.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-4 {
 | 
			
		||||
  width: 33.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-3 {
 | 
			
		||||
  width: 25%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-2 {
 | 
			
		||||
  width: 16.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-1 {
 | 
			
		||||
  width: 8.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-12 {
 | 
			
		||||
  right: 100%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-11 {
 | 
			
		||||
  right: 91.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-10 {
 | 
			
		||||
  right: 83.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-9 {
 | 
			
		||||
  right: 75%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-8 {
 | 
			
		||||
  right: 66.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-7 {
 | 
			
		||||
  right: 58.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-6 {
 | 
			
		||||
  right: 50%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-5 {
 | 
			
		||||
  right: 41.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-4 {
 | 
			
		||||
  right: 33.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-3 {
 | 
			
		||||
  right: 25%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-2 {
 | 
			
		||||
  right: 16.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-1 {
 | 
			
		||||
  right: 8.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-pull-0 {
 | 
			
		||||
  right: auto;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-12 {
 | 
			
		||||
  left: 100%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-11 {
 | 
			
		||||
  left: 91.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-10 {
 | 
			
		||||
  left: 83.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-9 {
 | 
			
		||||
  left: 75%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-8 {
 | 
			
		||||
  left: 66.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-7 {
 | 
			
		||||
  left: 58.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-6 {
 | 
			
		||||
  left: 50%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-5 {
 | 
			
		||||
  left: 41.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-4 {
 | 
			
		||||
  left: 33.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-3 {
 | 
			
		||||
  left: 25%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-2 {
 | 
			
		||||
  left: 16.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-1 {
 | 
			
		||||
  left: 8.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-push-0 {
 | 
			
		||||
  left: auto;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-12 {
 | 
			
		||||
  margin-left: 100%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-11 {
 | 
			
		||||
  margin-left: 91.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-10 {
 | 
			
		||||
  margin-left: 83.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-9 {
 | 
			
		||||
  margin-left: 75%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-8 {
 | 
			
		||||
  margin-left: 66.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-7 {
 | 
			
		||||
  margin-left: 58.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-6 {
 | 
			
		||||
  margin-left: 50%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-5 {
 | 
			
		||||
  margin-left: 41.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-4 {
 | 
			
		||||
  margin-left: 33.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-3 {
 | 
			
		||||
  margin-left: 25%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-2 {
 | 
			
		||||
  margin-left: 16.66666667%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-1 {
 | 
			
		||||
  margin-left: 8.33333333%;
 | 
			
		||||
}
 | 
			
		||||
.col-xs-offset-0 {
 | 
			
		||||
  margin-left: 0%;
 | 
			
		||||
}
 | 
			
		||||
@media (min-width: $screen-sm) {
 | 
			
		||||
  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-12 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-11 {
 | 
			
		||||
    width: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-10 {
 | 
			
		||||
    width: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-9 {
 | 
			
		||||
    width: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-8 {
 | 
			
		||||
    width: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-7 {
 | 
			
		||||
    width: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-6 {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-5 {
 | 
			
		||||
    width: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-4 {
 | 
			
		||||
    width: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-3 {
 | 
			
		||||
    width: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-2 {
 | 
			
		||||
    width: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-1 {
 | 
			
		||||
    width: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-12 {
 | 
			
		||||
    right: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-11 {
 | 
			
		||||
    right: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-10 {
 | 
			
		||||
    right: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-9 {
 | 
			
		||||
    right: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-8 {
 | 
			
		||||
    right: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-7 {
 | 
			
		||||
    right: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-6 {
 | 
			
		||||
    right: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-5 {
 | 
			
		||||
    right: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-4 {
 | 
			
		||||
    right: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-3 {
 | 
			
		||||
    right: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-2 {
 | 
			
		||||
    right: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-1 {
 | 
			
		||||
    right: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-pull-0 {
 | 
			
		||||
    right: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-12 {
 | 
			
		||||
    left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-11 {
 | 
			
		||||
    left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-10 {
 | 
			
		||||
    left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-9 {
 | 
			
		||||
    left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-8 {
 | 
			
		||||
    left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-7 {
 | 
			
		||||
    left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-6 {
 | 
			
		||||
    left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-5 {
 | 
			
		||||
    left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-4 {
 | 
			
		||||
    left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-3 {
 | 
			
		||||
    left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-2 {
 | 
			
		||||
    left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-1 {
 | 
			
		||||
    left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-push-0 {
 | 
			
		||||
    left: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-12 {
 | 
			
		||||
    margin-left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-11 {
 | 
			
		||||
    margin-left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-10 {
 | 
			
		||||
    margin-left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-9 {
 | 
			
		||||
    margin-left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-8 {
 | 
			
		||||
    margin-left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-7 {
 | 
			
		||||
    margin-left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-6 {
 | 
			
		||||
    margin-left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-5 {
 | 
			
		||||
    margin-left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-4 {
 | 
			
		||||
    margin-left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-3 {
 | 
			
		||||
    margin-left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-2 {
 | 
			
		||||
    margin-left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-1 {
 | 
			
		||||
    margin-left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-sm-offset-0 {
 | 
			
		||||
    margin-left: 0%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (min-width: $screen-md) {
 | 
			
		||||
  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-12 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-11 {
 | 
			
		||||
    width: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-10 {
 | 
			
		||||
    width: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-9 {
 | 
			
		||||
    width: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-8 {
 | 
			
		||||
    width: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-7 {
 | 
			
		||||
    width: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-6 {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-5 {
 | 
			
		||||
    width: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-4 {
 | 
			
		||||
    width: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-3 {
 | 
			
		||||
    width: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-2 {
 | 
			
		||||
    width: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-1 {
 | 
			
		||||
    width: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-12 {
 | 
			
		||||
    right: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-11 {
 | 
			
		||||
    right: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-10 {
 | 
			
		||||
    right: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-9 {
 | 
			
		||||
    right: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-8 {
 | 
			
		||||
    right: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-7 {
 | 
			
		||||
    right: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-6 {
 | 
			
		||||
    right: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-5 {
 | 
			
		||||
    right: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-4 {
 | 
			
		||||
    right: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-3 {
 | 
			
		||||
    right: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-2 {
 | 
			
		||||
    right: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-1 {
 | 
			
		||||
    right: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-pull-0 {
 | 
			
		||||
    right: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-12 {
 | 
			
		||||
    left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-11 {
 | 
			
		||||
    left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-10 {
 | 
			
		||||
    left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-9 {
 | 
			
		||||
    left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-8 {
 | 
			
		||||
    left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-7 {
 | 
			
		||||
    left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-6 {
 | 
			
		||||
    left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-5 {
 | 
			
		||||
    left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-4 {
 | 
			
		||||
    left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-3 {
 | 
			
		||||
    left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-2 {
 | 
			
		||||
    left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-1 {
 | 
			
		||||
    left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-push-0 {
 | 
			
		||||
    left: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-12 {
 | 
			
		||||
    margin-left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-11 {
 | 
			
		||||
    margin-left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-10 {
 | 
			
		||||
    margin-left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-9 {
 | 
			
		||||
    margin-left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-8 {
 | 
			
		||||
    margin-left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-7 {
 | 
			
		||||
    margin-left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-6 {
 | 
			
		||||
    margin-left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-5 {
 | 
			
		||||
    margin-left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-4 {
 | 
			
		||||
    margin-left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-3 {
 | 
			
		||||
    margin-left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-2 {
 | 
			
		||||
    margin-left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-1 {
 | 
			
		||||
    margin-left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-md-offset-0 {
 | 
			
		||||
    margin-left: 0%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (min-width: $screen-lg) {
 | 
			
		||||
  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-12 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-11 {
 | 
			
		||||
    width: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-10 {
 | 
			
		||||
    width: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-9 {
 | 
			
		||||
    width: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-8 {
 | 
			
		||||
    width: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-7 {
 | 
			
		||||
    width: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-6 {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-5 {
 | 
			
		||||
    width: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-4 {
 | 
			
		||||
    width: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-3 {
 | 
			
		||||
    width: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-2 {
 | 
			
		||||
    width: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-1 {
 | 
			
		||||
    width: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-12 {
 | 
			
		||||
    right: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-11 {
 | 
			
		||||
    right: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-10 {
 | 
			
		||||
    right: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-9 {
 | 
			
		||||
    right: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-8 {
 | 
			
		||||
    right: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-7 {
 | 
			
		||||
    right: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-6 {
 | 
			
		||||
    right: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-5 {
 | 
			
		||||
    right: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-4 {
 | 
			
		||||
    right: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-3 {
 | 
			
		||||
    right: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-2 {
 | 
			
		||||
    right: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-1 {
 | 
			
		||||
    right: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-pull-0 {
 | 
			
		||||
    right: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-12 {
 | 
			
		||||
    left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-11 {
 | 
			
		||||
    left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-10 {
 | 
			
		||||
    left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-9 {
 | 
			
		||||
    left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-8 {
 | 
			
		||||
    left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-7 {
 | 
			
		||||
    left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-6 {
 | 
			
		||||
    left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-5 {
 | 
			
		||||
    left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-4 {
 | 
			
		||||
    left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-3 {
 | 
			
		||||
    left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-2 {
 | 
			
		||||
    left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-1 {
 | 
			
		||||
    left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-push-0 {
 | 
			
		||||
    left: auto;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-12 {
 | 
			
		||||
    margin-left: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-11 {
 | 
			
		||||
    margin-left: 91.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-10 {
 | 
			
		||||
    margin-left: 83.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-9 {
 | 
			
		||||
    margin-left: 75%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-8 {
 | 
			
		||||
    margin-left: 66.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-7 {
 | 
			
		||||
    margin-left: 58.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-6 {
 | 
			
		||||
    margin-left: 50%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-5 {
 | 
			
		||||
    margin-left: 41.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-4 {
 | 
			
		||||
    margin-left: 33.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-3 {
 | 
			
		||||
    margin-left: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-2 {
 | 
			
		||||
    margin-left: 16.66666667%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-1 {
 | 
			
		||||
    margin-left: 8.33333333%;
 | 
			
		||||
  }
 | 
			
		||||
  .col-lg-offset-0 {
 | 
			
		||||
    margin-left: 0%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.clearfix:before,
 | 
			
		||||
.clearfix:after,
 | 
			
		||||
.container:before,
 | 
			
		||||
.container:after,
 | 
			
		||||
.container-fluid:before,
 | 
			
		||||
.container-fluid:after,
 | 
			
		||||
.row:before,
 | 
			
		||||
.row:after {
 | 
			
		||||
  content: " ";
 | 
			
		||||
  display: table;
 | 
			
		||||
}
 | 
			
		||||
.clearfix:after,
 | 
			
		||||
.container:after,
 | 
			
		||||
.container-fluid:after,
 | 
			
		||||
.row:after {
 | 
			
		||||
  clear: both;
 | 
			
		||||
}
 | 
			
		||||
.center-block {
 | 
			
		||||
  display: block;
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,21 +2,31 @@
 | 
			
		|||
 * Includes the main navigation header and the faded toolbar.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
header .grid {
 | 
			
		||||
  grid-template-columns: auto min-content auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  header .grid {
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
    grid-row-gap: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  display: block;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  z-index: 6;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  background-color: $primary-dark;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  fill: #fff;
 | 
			
		||||
  .padded {
 | 
			
		||||
    padding: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  border-bottom: 1px solid #DDD;
 | 
			
		||||
  box-shadow: $bs-card;
 | 
			
		||||
  padding: $-xxs 0;
 | 
			
		||||
  .links {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: top;
 | 
			
		||||
    margin-left: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  .links a {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,15 +38,6 @@ header {
 | 
			
		|||
    padding-left: $-m;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($screen-md) {
 | 
			
		||||
    .links a {
 | 
			
		||||
      padding-left: $-s;
 | 
			
		||||
      padding-right: $-s;
 | 
			
		||||
    }
 | 
			
		||||
    .dropdown-container {
 | 
			
		||||
      padding-left: $-s;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .avatar, .user-name {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -63,27 +64,17 @@ header {
 | 
			
		|||
      padding-top: 4px;
 | 
			
		||||
      font-size: 18px;
 | 
			
		||||
    }
 | 
			
		||||
    @include smaller-than($screen-md) {
 | 
			
		||||
    @include between($l, $xl) {
 | 
			
		||||
      padding-left: $-xs;
 | 
			
		||||
      .name {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($screen-sm) {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    .float.right {
 | 
			
		||||
      float: none;
 | 
			
		||||
    }
 | 
			
		||||
    .links a {
 | 
			
		||||
      padding: $-s;
 | 
			
		||||
    }
 | 
			
		||||
    .user-name {
 | 
			
		||||
      padding-top: $-s;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.header-search {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -92,13 +83,16 @@ header .search-box {
 | 
			
		|||
  margin-top: 10px;
 | 
			
		||||
  input {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.2);
 | 
			
		||||
    border: 1px solid rgba(255, 255, 255, 0.3);
 | 
			
		||||
    border: 1px solid rgba(255, 255, 255, 0.2);
 | 
			
		||||
    border-radius: 40px;
 | 
			
		||||
    color: #EEE;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
    padding-left: 40px;
 | 
			
		||||
  }
 | 
			
		||||
  button {
 | 
			
		||||
    fill: #EEE;
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
    left: 16px;
 | 
			
		||||
    svg {
 | 
			
		||||
      margin-right: 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -115,20 +109,11 @@ header .search-box {
 | 
			
		|||
  :-moz-placeholder { /* Firefox 18- */
 | 
			
		||||
    color: #DDD;
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($screen-lg) {
 | 
			
		||||
    max-width: 250px;
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($l) {
 | 
			
		||||
  @include between($l, $xl) {
 | 
			
		||||
    max-width: 200px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($s) {
 | 
			
		||||
  .header-search {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logo {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  &:hover {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,10 +136,184 @@ header .search-box {
 | 
			
		|||
  height: 43px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumbs span.sep {
 | 
			
		||||
  color: #aaa;
 | 
			
		||||
.mobile-menu-toggle {
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  fill: #FFF;
 | 
			
		||||
  font-size: 2em;
 | 
			
		||||
  border: 2px solid rgba(255, 255, 255, 0.8);
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  padding: 0 $-xs;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: $-m;
 | 
			
		||||
  top: 13px;
 | 
			
		||||
  line-height: 1;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  svg {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    bottom: -2px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  header .header-links {
 | 
			
		||||
    display: none;
 | 
			
		||||
    background-color: #FFF;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    right: $-m;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    box-shadow: $bs-hover;
 | 
			
		||||
    margin-top: -$-xs;
 | 
			
		||||
    &.show {
 | 
			
		||||
      display: block;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  header .links a, header .dropdown-container ul li a {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    display: block;
 | 
			
		||||
    padding: $-s $-m;
 | 
			
		||||
    color: $text-dark;
 | 
			
		||||
    fill: $text-dark;
 | 
			
		||||
    svg {
 | 
			
		||||
      margin-right: $-s;
 | 
			
		||||
    }
 | 
			
		||||
    &:hover {
 | 
			
		||||
      background-color: #EEE;
 | 
			
		||||
      color: #444;
 | 
			
		||||
      fill: #444;
 | 
			
		||||
      text-decoration: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  header .dropdown-container {
 | 
			
		||||
    display: block;
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
  }
 | 
			
		||||
  header .links {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  header .dropdown-container ul {
 | 
			
		||||
    display: block !important;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tri-layout-mobile-tabs {
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  z-index: 5;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  border-bottom: 1px solid #DDD;
 | 
			
		||||
  box-shadow: $bs-card;
 | 
			
		||||
}
 | 
			
		||||
.tri-layout-mobile-tab {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-bottom: 3px solid #BBB;
 | 
			
		||||
  &:first-child {
 | 
			
		||||
    border-right: 1px solid #DDD;
 | 
			
		||||
  }
 | 
			
		||||
  &.active {
 | 
			
		||||
    border-bottom-color: currentColor;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumbs {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: flex-start;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  opacity: 0.7;
 | 
			
		||||
  .icon-list-item {
 | 
			
		||||
    width: auto;
 | 
			
		||||
    padding-top: $-xs;
 | 
			
		||||
    padding-bottom: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
  .separator {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    fill: #aaa;
 | 
			
		||||
    font-size: 1.6em;
 | 
			
		||||
    line-height: 0.8;
 | 
			
		||||
    margin: -2px 0 0;
 | 
			
		||||
  }
 | 
			
		||||
  &:hover {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  .breadcrumbs .icon-list-item {
 | 
			
		||||
    padding: $-xs;
 | 
			
		||||
    > span + span {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
    > span:first-child {
 | 
			
		||||
      margin-right: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumb-listing {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  .breadcrumb-listing-toggle {
 | 
			
		||||
    padding: 6px;
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    &:hover {
 | 
			
		||||
      border-color: #DDD;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .svg-icon {
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumb-listing-dropdown {
 | 
			
		||||
  box-shadow: $bs-med;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  min-height: 100px;
 | 
			
		||||
  width: 240px;
 | 
			
		||||
  display: none;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 80;
 | 
			
		||||
  right: -$-m;
 | 
			
		||||
  .breadcrumb-listing-search .svg-icon {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: $-s;
 | 
			
		||||
    top: 11px;
 | 
			
		||||
    fill: #888;
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumb-listing-entity-list {
 | 
			
		||||
    max-height: 400px;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  }
 | 
			
		||||
  input {
 | 
			
		||||
    padding-left: $-xl;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
    border: 0;
 | 
			
		||||
    border-bottom: 1px solid #DDD;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .breadcrumb-listing-dropdown {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    right: auto;
 | 
			
		||||
    left: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumb-listing-dropdown .breadcrumb-listing-entity-list {
 | 
			
		||||
    max-height: 240px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.faded {
 | 
			
		||||
  a, button, span, span > div {
 | 
			
		||||
    color: #666;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,20 +334,9 @@ header .search-box {
 | 
			
		|||
  padding: $-s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.faded-small {
 | 
			
		||||
  color: #000;
 | 
			
		||||
  fill: #000;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  background-color: $primary-faded;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.toolbar-container {
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumbs .text-button, .action-buttons .text-button {
 | 
			
		||||
.action-buttons .text-button {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  padding: $-s;
 | 
			
		||||
  padding: $-xs $-s;
 | 
			
		||||
  &:last-child {
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -217,28 +365,12 @@ header .search-box {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .breadcrumbs .text-button, .action-buttons .text-button {
 | 
			
		||||
  .action-buttons .text-button {
 | 
			
		||||
    padding: $-xs $-xs;
 | 
			
		||||
  }
 | 
			
		||||
  .action-buttons .dropdown-container:last-child a {
 | 
			
		||||
    padding-left: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumbs .text-button {
 | 
			
		||||
    font-size: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumbs .text-button svg {
 | 
			
		||||
    font-size: $fs-m;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumbs a i {
 | 
			
		||||
    font-size: $fs-m;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .breadcrumbs span.sep {
 | 
			
		||||
    padding: 0 $-xxs;
 | 
			
		||||
  }
 | 
			
		||||
  .toolbar .col-xs-1:first-child {
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.nav-tabs {
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +385,4 @@ header .search-box {
 | 
			
		|||
      border-bottom: 2px solid $primary;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.faded-small .nav-tabs a {
 | 
			
		||||
  padding: $-s $-m;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,27 +3,18 @@
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
html {
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  background-color: #F2F2F2;
 | 
			
		||||
  &.flexbox {
 | 
			
		||||
    overflow-y: hidden;
 | 
			
		||||
  }
 | 
			
		||||
  &.shaded {
 | 
			
		||||
    background-color: #F2F2F2;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  font-size: $fs-m;
 | 
			
		||||
  line-height: 1.6;
 | 
			
		||||
  color: #616161;
 | 
			
		||||
  color: #444;
 | 
			
		||||
  -webkit-font-smoothing: antialiased;
 | 
			
		||||
  &.shaded {
 | 
			
		||||
    background-color: #F2F2F2;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button {
 | 
			
		||||
  font-size: 100%;
 | 
			
		||||
  background-color: #F2F2F2;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,312 @@
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * Generic content container
 | 
			
		||||
 */
 | 
			
		||||
.container {
 | 
			
		||||
  max-width: $xxl;
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  padding-right: $-m;
 | 
			
		||||
  &.small {
 | 
			
		||||
    max-width: 840px;
 | 
			
		||||
  }
 | 
			
		||||
  &.very-small {
 | 
			
		||||
    max-width: 480px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Core grid layout system
 | 
			
		||||
 */
 | 
			
		||||
.grid {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-column-gap: $-l;
 | 
			
		||||
  grid-row-gap: $-l;
 | 
			
		||||
  &.half {
 | 
			
		||||
    grid-template-columns: 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  &.third {
 | 
			
		||||
    grid-template-columns: 1fr 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  &.left-focus {
 | 
			
		||||
    grid-template-columns: 2fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  &.right-focus {
 | 
			
		||||
    grid-template-columns: 1fr 3fr;
 | 
			
		||||
  }
 | 
			
		||||
  &.gap-y-xs {
 | 
			
		||||
    grid-row-gap: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
  &.gap-xl {
 | 
			
		||||
    grid-column-gap: $-xl;
 | 
			
		||||
    grid-row-gap: $-xl;
 | 
			
		||||
  }
 | 
			
		||||
  &.gap-xxl {
 | 
			
		||||
    grid-column-gap: $-xxl;
 | 
			
		||||
    grid-row-gap: $-xxl;
 | 
			
		||||
  }
 | 
			
		||||
  &.v-center {
 | 
			
		||||
    align-items: center;
 | 
			
		||||
  }
 | 
			
		||||
  &.no-gap {
 | 
			
		||||
    grid-row-gap: 0;
 | 
			
		||||
    grid-column-gap: 0;
 | 
			
		||||
  }
 | 
			
		||||
  &.no-row-gap {
 | 
			
		||||
    grid-row-gap: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .grid.third {
 | 
			
		||||
    grid-template-columns: 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  .grid.half:not(.no-break), .grid.left-focus:not(.no-break), .grid.right-focus:not(.no-break) {
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  .grid.half.collapse-xs {
 | 
			
		||||
    grid-template-columns: 1fr 1fr;
 | 
			
		||||
  }
 | 
			
		||||
  .grid.gap-xl {
 | 
			
		||||
    grid-column-gap: $-m;
 | 
			
		||||
    grid-row-gap: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  .grid.right-focus.reverse-collapse > *:nth-child(2) {
 | 
			
		||||
    order: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .grid.right-focus.reverse-collapse > *:nth-child(1) {
 | 
			
		||||
    order: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($s) {
 | 
			
		||||
  .grid.third {
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($xs) {
 | 
			
		||||
  .grid.half.collapse-xs {
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Flexbox layout system
 | 
			
		||||
 */
 | 
			
		||||
body.flexbox {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  #content {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    min-height: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-fill {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  min-height: 0;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  min-height: 0;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display and float utilities
 | 
			
		||||
 */
 | 
			
		||||
.block {
 | 
			
		||||
  display: block;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inline {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.block.inline {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.float {
 | 
			
		||||
  float: left;
 | 
			
		||||
  &.right {
 | 
			
		||||
    float: right;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Visibility
 | 
			
		||||
 */
 | 
			
		||||
@each $sizeLetter, $size in $screen-sizes {
 | 
			
		||||
  @include smaller-than($size) {
 | 
			
		||||
    .hide-under-#{$sizeLetter} {
 | 
			
		||||
      display: none !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  @include larger-than($size) {
 | 
			
		||||
    .hide-over-#{$sizeLetter} {
 | 
			
		||||
      display: none !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Inline content columns
 | 
			
		||||
 */
 | 
			
		||||
.dual-column-content {
 | 
			
		||||
  columns: 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .dual-column-content {
 | 
			
		||||
    columns: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fixes
 | 
			
		||||
 */
 | 
			
		||||
.clearfix:before,
 | 
			
		||||
.clearfix:after {
 | 
			
		||||
  content: " ";
 | 
			
		||||
  display: table;
 | 
			
		||||
}
 | 
			
		||||
.clearfix:after {
 | 
			
		||||
  clear: both;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * View Layouts
 | 
			
		||||
 */
 | 
			
		||||
.tri-layout-container {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  margin-left: $-xl;
 | 
			
		||||
  margin-right: $-xl;
 | 
			
		||||
  grid-template-columns: 1fr 4fr 1fr;
 | 
			
		||||
  grid-template-areas: "a b c";
 | 
			
		||||
  grid-column-gap: $-xxl;
 | 
			
		||||
  .tri-layout-right {
 | 
			
		||||
    grid-area: c;
 | 
			
		||||
    min-width: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .tri-layout-left {
 | 
			
		||||
    grid-area: a;
 | 
			
		||||
    min-width: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .tri-layout-middle {
 | 
			
		||||
    grid-area: b;
 | 
			
		||||
    padding-top: $-m;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include smaller-than($xxl) {
 | 
			
		||||
  .tri-layout-container {
 | 
			
		||||
    grid-template-areas:  "c b b"
 | 
			
		||||
    "a b b";
 | 
			
		||||
    grid-template-columns: 1fr 3fr;
 | 
			
		||||
    grid-template-rows: max-content min-content;
 | 
			
		||||
    padding-right: $-l;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include larger-than($xxl) {
 | 
			
		||||
  .tri-layout-left-contents, .tri-layout-right-contents {
 | 
			
		||||
    padding: $-m;
 | 
			
		||||
    position: sticky;
 | 
			
		||||
    top: $-m;
 | 
			
		||||
    max-height: 100vh;
 | 
			
		||||
    min-height: 50vh;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
    overflow-x: hidden;
 | 
			
		||||
    scrollbar-width: none;
 | 
			
		||||
    -ms-overflow-style: none;
 | 
			
		||||
    &::-webkit-scrollbar {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .tri-layout-middle-contents {
 | 
			
		||||
    max-width: 940px;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  .tri-layout-container {
 | 
			
		||||
    grid-template-areas:  none;
 | 
			
		||||
    grid-template-columns: 1fr;
 | 
			
		||||
    grid-column-gap: 0;
 | 
			
		||||
    padding-right: $-xs;
 | 
			
		||||
    padding-left: $-xs;
 | 
			
		||||
    .tri-layout-left-contents, .tri-layout-right-contents {
 | 
			
		||||
      padding-left: $-m;
 | 
			
		||||
      padding-right: $-m;
 | 
			
		||||
    }
 | 
			
		||||
    .tri-layout-right-contents > div, .tri-layout-left-contents > div {
 | 
			
		||||
      opacity: 0.6;
 | 
			
		||||
      z-index: 0;
 | 
			
		||||
    }
 | 
			
		||||
    .tri-layout-left > *, .tri-layout-right > * {
 | 
			
		||||
      display: none;
 | 
			
		||||
      pointer-events: none;
 | 
			
		||||
    }
 | 
			
		||||
    .tri-layout-left, .tri-layout-right {
 | 
			
		||||
      grid-area: none;
 | 
			
		||||
      grid-column: 1/1;
 | 
			
		||||
      grid-row: 1;
 | 
			
		||||
      padding-top: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
    .tri-layout-middle {
 | 
			
		||||
      grid-area: none;
 | 
			
		||||
      grid-row: 3;
 | 
			
		||||
      grid-column: 1/1;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      transition: transform ease-in-out 240ms;
 | 
			
		||||
    }
 | 
			
		||||
    .tri-layout-left {
 | 
			
		||||
      grid-row: 2;
 | 
			
		||||
    }
 | 
			
		||||
    &.show-info {
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      .tri-layout-middle {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
      .tri-layout-right  > *, .tri-layout-left > * {
 | 
			
		||||
        display: block;
 | 
			
		||||
        pointer-events: auto;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include larger-than($l) {
 | 
			
		||||
  .tri-layout-mobile-tabs {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($m) {
 | 
			
		||||
  .tri-layout-container {
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tri-layout-left-contents > div, .tri-layout-right-contents > div {
 | 
			
		||||
  opacity: 0.6;
 | 
			
		||||
  transition: opacity ease-in-out 120ms;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,182 +1,217 @@
 | 
			
		|||
.page-list {
 | 
			
		||||
  h4 {
 | 
			
		||||
    margin: $-l 0 $-xs 0;
 | 
			
		||||
    font-size: 1.666em;
 | 
			
		||||
 | 
			
		||||
.book-contents .entity-list-item {
 | 
			
		||||
  .icon {
 | 
			
		||||
    width: 4px;
 | 
			
		||||
    border-radius: 1px;
 | 
			
		||||
    justify-self: stretch;
 | 
			
		||||
    align-self: stretch;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    margin-right: $-l;
 | 
			
		||||
  }
 | 
			
		||||
  a.chapter {
 | 
			
		||||
    color: $color-chapter;
 | 
			
		||||
  .icon:after {
 | 
			
		||||
    opacity: 0.5;
 | 
			
		||||
  }
 | 
			
		||||
  .inset-list {
 | 
			
		||||
  .icon svg {
 | 
			
		||||
    display: none;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
  }
 | 
			
		||||
  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;
 | 
			
		||||
    }
 | 
			
		||||
  p {
 | 
			
		||||
    margin-bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item {
 | 
			
		||||
    margin-bottom: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  hr {
 | 
			
		||||
    margin-top: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .page, .chapter, .book {
 | 
			
		||||
    padding-left: $-l;
 | 
			
		||||
  }
 | 
			
		||||
  .page {
 | 
			
		||||
    border-left: 5px solid $color-page;
 | 
			
		||||
  }
 | 
			
		||||
  .page.draft {
 | 
			
		||||
    border-left: 5px solid $color-page-draft;
 | 
			
		||||
    .text-page {
 | 
			
		||||
      color: $color-page-draft;
 | 
			
		||||
      fill: $color-page-draft;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .chapter {
 | 
			
		||||
    border-left: 5px solid $color-chapter;
 | 
			
		||||
  }
 | 
			
		||||
  .book {
 | 
			
		||||
    border-left: 5px solid $color-book;
 | 
			
		||||
  }
 | 
			
		||||
  .meta {
 | 
			
		||||
    margin-top: -$-m;
 | 
			
		||||
    font-size: 0.95em;
 | 
			
		||||
  }
 | 
			
		||||
  .meta span {
 | 
			
		||||
    margin-right: $-s;
 | 
			
		||||
  .inner-page {
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($s) {
 | 
			
		||||
  .page-list h4 {
 | 
			
		||||
    font-size: 1.333em;
 | 
			
		||||
.entity-list-item + .chapter-expansion {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  padding: 0 $-m $-m $-m;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  border: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  > .icon {
 | 
			
		||||
    width: 4px;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    border-radius: 0 0 1px 1px;
 | 
			
		||||
    align-self: stretch;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
    &:before {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: 0;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 1px;
 | 
			
		||||
      background-color: currentColor;
 | 
			
		||||
      content: '';
 | 
			
		||||
      opacity: 0.5;
 | 
			
		||||
    }
 | 
			
		||||
    &:after {
 | 
			
		||||
      opacity: 0.5;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .icon svg {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  > .content {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
  }
 | 
			
		||||
  .chapter-expansion-toggle {
 | 
			
		||||
    border-radius: 0 4px 4px 0;
 | 
			
		||||
    padding: $-xs $-m;
 | 
			
		||||
  }
 | 
			
		||||
  .chapter-expansion-toggle:hover {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.06);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item.has-children {
 | 
			
		||||
  padding-bottom: 0;
 | 
			
		||||
  > .icon {
 | 
			
		||||
    border-radius: 4px 4px 0 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inset-list {
 | 
			
		||||
  display: none;
 | 
			
		||||
  .entity-list-item-name {
 | 
			
		||||
    font-size: 1rem;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item-children {
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-page-nav {
 | 
			
		||||
  $nav-indent: $-s;
 | 
			
		||||
  $nav-indent: $-m;
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  margin: $-s 0 $-m 2px;
 | 
			
		||||
  border-left: 2px dotted #BBB;
 | 
			
		||||
  margin: $-s 0 $-m $-xs;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  &:after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.2);
 | 
			
		||||
    width: 2px;
 | 
			
		||||
    top: 5px;
 | 
			
		||||
    bottom: 5px;
 | 
			
		||||
    z-index: 0;
 | 
			
		||||
  }
 | 
			
		||||
  li {
 | 
			
		||||
    padding-left: $-s;
 | 
			
		||||
    margin-bottom: 4px;
 | 
			
		||||
    font-size: 0.95em;
 | 
			
		||||
    position: relative;
 | 
			
		||||
  }
 | 
			
		||||
  .h1 {
 | 
			
		||||
    margin-left: -2px;
 | 
			
		||||
    padding-left: $nav-indent;
 | 
			
		||||
  }
 | 
			
		||||
  .h2 {
 | 
			
		||||
    margin-left: -2px;
 | 
			
		||||
    padding-left: $nav-indent;
 | 
			
		||||
  }
 | 
			
		||||
  .h3 {
 | 
			
		||||
    margin-left: $nav-indent;
 | 
			
		||||
    padding-left: $nav-indent * 2;
 | 
			
		||||
  }
 | 
			
		||||
  .h4 {
 | 
			
		||||
    margin-left: $nav-indent*2;
 | 
			
		||||
    padding-left: $nav-indent * 2.5;
 | 
			
		||||
  }
 | 
			
		||||
  .h5 {
 | 
			
		||||
    margin-left: $nav-indent*3;
 | 
			
		||||
    padding-left: $nav-indent*3;
 | 
			
		||||
  }
 | 
			
		||||
  .h6 {
 | 
			
		||||
    margin-left: $nav-indent*4;
 | 
			
		||||
    padding-left: $nav-indent*3.5;
 | 
			
		||||
  }
 | 
			
		||||
  .current-heading {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
  }
 | 
			
		||||
  li:not(.current-heading) .sidebar-page-nav-bullet {
 | 
			
		||||
    background-color: #BBB !important;
 | 
			
		||||
  }
 | 
			
		||||
  .sidebar-page-nav-bullet {
 | 
			
		||||
    width: 6px;
 | 
			
		||||
    height: 6px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: -2px;
 | 
			
		||||
    top: 30%;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    box-shadow: 0 0 0 6px #F2F2F2;
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sidebar list
 | 
			
		||||
.book-tree {
 | 
			
		||||
  transition: ease-in-out 240ms;
 | 
			
		||||
  transition-property: right, border;
 | 
			
		||||
}
 | 
			
		||||
.book-tree h4 {
 | 
			
		||||
  padding: $-m $-s 0 $-s;
 | 
			
		||||
  i {
 | 
			
		||||
    padding-right: $-s;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.book-tree .sidebar-page-list {
 | 
			
		||||
.book-tree .sidebar-page-list  {
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  margin: $-xs 0 0;
 | 
			
		||||
  margin: $-xs -$-s 0 -$-s;
 | 
			
		||||
  padding-left: 0;
 | 
			
		||||
  border-left: 5px solid $color-book;
 | 
			
		||||
  li a {
 | 
			
		||||
  padding-right: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
 | 
			
		||||
  &:after, .sub-menu:after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
    border-bottom: none;
 | 
			
		||||
    padding: $-xs 0 $-xs $-s;
 | 
			
		||||
    &:hover {
 | 
			
		||||
      text-decoration: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  li a i {
 | 
			
		||||
    padding-right: $-xs + 2px;
 | 
			
		||||
  }
 | 
			
		||||
  li, a {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  a.bold {
 | 
			
		||||
    color: #EEE !important;
 | 
			
		||||
    fill: #EEE !important;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: $-m;
 | 
			
		||||
    top: 1rem;
 | 
			
		||||
    bottom: 1rem;
 | 
			
		||||
    border-left: 4px solid rgba(0, 0, 0, 0.1);
 | 
			
		||||
    z-index: 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ul {
 | 
			
		||||
    list-style: none;
 | 
			
		||||
    padding-left: 1rem;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item {
 | 
			
		||||
    padding-top: $-xxs;
 | 
			
		||||
    padding-bottom: $-xxs;
 | 
			
		||||
    .content {
 | 
			
		||||
      padding-top: $-xs;
 | 
			
		||||
      padding-bottom: $-xs;
 | 
			
		||||
      max-width: calc(100% - 20px);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item.no-hover {
 | 
			
		||||
    margin-top: -$-xs;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item-name {
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .book {
 | 
			
		||||
    color: $color-book !important;
 | 
			
		||||
    fill: $color-book !important;
 | 
			
		||||
    &.selected {
 | 
			
		||||
      background-color: rgba($color-book, 0.29);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .chapter {
 | 
			
		||||
    color: $color-chapter !important;
 | 
			
		||||
    fill: $color-chapter !important;
 | 
			
		||||
    &.selected {
 | 
			
		||||
      background-color: rgba($color-chapter, 0.12);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .page {
 | 
			
		||||
    color: $color-page !important;
 | 
			
		||||
    fill: $color-page !important;
 | 
			
		||||
    border-bottom: none;
 | 
			
		||||
    &.selected {
 | 
			
		||||
      background-color: rgba($color-page, 0.1);
 | 
			
		||||
    }
 | 
			
		||||
  .chapter-child-menu {
 | 
			
		||||
    font-size: .8rem;
 | 
			
		||||
    margin-top: -.2rem;
 | 
			
		||||
    margin-left: -1rem;
 | 
			
		||||
  }
 | 
			
		||||
  [chapter-toggle] {
 | 
			
		||||
    padding-left: $-s;
 | 
			
		||||
    padding-left: .7rem;
 | 
			
		||||
    padding-bottom: .2rem;
 | 
			
		||||
  }
 | 
			
		||||
  .list-item-chapter {
 | 
			
		||||
    border-left: 5px solid $color-chapter;
 | 
			
		||||
    margin: 10px 10px;
 | 
			
		||||
    display: block;
 | 
			
		||||
  .entity-list-item .icon {
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
    width: 4px;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    align-self: stretch;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
    border-radius: 1px;
 | 
			
		||||
    opacity: 0.6;
 | 
			
		||||
  }
 | 
			
		||||
  .list-item-page {
 | 
			
		||||
    border-bottom: none;
 | 
			
		||||
    border-left: 5px solid $color-page;
 | 
			
		||||
    margin: 10px 10px;
 | 
			
		||||
  .entity-list-item .icon:after {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
  }
 | 
			
		||||
  .list-item-page.draft {
 | 
			
		||||
    border-left: 5px solid $color-page-draft;
 | 
			
		||||
  .entity-list-item .icon svg {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  .page.draft .page, .list-item-page.draft a.page {
 | 
			
		||||
    color: $color-page-draft !important;
 | 
			
		||||
    fill: $color-page-draft !important;
 | 
			
		||||
  }
 | 
			
		||||
  .sub-menu {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.chapter-child-menu {
 | 
			
		||||
  ul.sub-menu {
 | 
			
		||||
    display: none;
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
    position: relative;
 | 
			
		||||
  }
 | 
			
		||||
  [chapter-toggle].open + .sub-menu {
 | 
			
		||||
    display: block;
 | 
			
		||||
| 
						 | 
				
			
			@ -186,26 +221,41 @@
 | 
			
		|||
// Sortable Lists
 | 
			
		||||
.sortable-page-list, .sortable-page-list ul {
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
}
 | 
			
		||||
.sort-box {
 | 
			
		||||
  margin-bottom: $-m;
 | 
			
		||||
  padding: 0 $-l 0 $-l;
 | 
			
		||||
  border-left: 4px solid $color-book;
 | 
			
		||||
  border: 2px solid rgba($color-book, 0.6);
 | 
			
		||||
  padding: $-m $-xl;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
.sort-box-options {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
.sort-box-options .button {
 | 
			
		||||
  margin-left: 0;
 | 
			
		||||
}
 | 
			
		||||
.sortable-page-list {
 | 
			
		||||
  margin-left: 0;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  .entity-list-item > span:first-child {
 | 
			
		||||
    align-self: flex-start;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item > div {
 | 
			
		||||
    display: block;
 | 
			
		||||
    flex: 1;
 | 
			
		||||
  }
 | 
			
		||||
  > ul {
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
  }
 | 
			
		||||
  ul {
 | 
			
		||||
    margin-bottom: 0;
 | 
			
		||||
    margin-bottom: $-m;
 | 
			
		||||
    margin-top: 0;
 | 
			
		||||
    box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.1);
 | 
			
		||||
    padding-left: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  li {
 | 
			
		||||
    border: 1px solid #DDD;
 | 
			
		||||
    padding: $-xs $-s;
 | 
			
		||||
    margin-top: -1px;
 | 
			
		||||
    min-height: 38px;
 | 
			
		||||
    &.text-chapter {
 | 
			
		||||
| 
						 | 
				
			
			@ -228,18 +278,26 @@
 | 
			
		|||
 | 
			
		||||
.activity-list-item {
 | 
			
		||||
  padding: $-s 0;
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: min-content 1fr;
 | 
			
		||||
  grid-column-gap: $-m;
 | 
			
		||||
  color: #888;
 | 
			
		||||
  fill: #888;
 | 
			
		||||
  border-bottom: 1px solid #EEE;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  .left {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
  .left + .right {
 | 
			
		||||
    margin-left: 30px + $-s;
 | 
			
		||||
  }
 | 
			
		||||
  &:last-of-type {
 | 
			
		||||
    border-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
.card .activity-list-item {
 | 
			
		||||
  padding: $-s $-m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-list-item {
 | 
			
		||||
  display: inline-grid;
 | 
			
		||||
  padding: $-s;
 | 
			
		||||
  grid-template-columns: min-content 1fr;
 | 
			
		||||
  grid-column-gap: $-m;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  > div:first-child {
 | 
			
		||||
    line-height: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -280,10 +338,8 @@ ul.pagination {
 | 
			
		|||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list {
 | 
			
		||||
  > div {
 | 
			
		||||
    padding: $-m 0;
 | 
			
		||||
  }
 | 
			
		||||
.entity-list, .icon-list {
 | 
			
		||||
  margin: 0 (-$-m);
 | 
			
		||||
  h4 {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -302,15 +358,125 @@ ul.pagination {
 | 
			
		|||
    color: $color-page-draft;
 | 
			
		||||
    fill: $color-page-draft;
 | 
			
		||||
  }
 | 
			
		||||
  > .dropdown-container {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card .entity-list-item, .card .activity-list-item {
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  padding-right: $-m;
 | 
			
		||||
.icon-list hr {
 | 
			
		||||
  margin: $-s $-m;
 | 
			
		||||
  max-width: 140px;
 | 
			
		||||
  opacity: 0.25;
 | 
			
		||||
  height: 1.1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.icon-list hr + hr, .icon-list hr:first-child, .icon-list hr:last-child {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item, .icon-list-item {
 | 
			
		||||
  padding: $-s $-m;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  border: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  word-break: break-word;
 | 
			
		||||
  h4 a {
 | 
			
		||||
    color: #666;
 | 
			
		||||
  }
 | 
			
		||||
  > span:first-child {
 | 
			
		||||
    margin-right: $-m;
 | 
			
		||||
    flex-basis: 1.88em;
 | 
			
		||||
    flex: none;
 | 
			
		||||
  }
 | 
			
		||||
  > span:last-child {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  }
 | 
			
		||||
  &:not(.no-hover) {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
  &:not(.no-hover):hover {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.1);
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
  }
 | 
			
		||||
  &.outline-hover {
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
  }
 | 
			
		||||
  &.outline-hover:hover {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item-path-sep {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  vertical-align: top;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 1px;
 | 
			
		||||
  svg {
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card .entity-list-item:not(.no-hover):hover {
 | 
			
		||||
  background-color: #F2F2F2;
 | 
			
		||||
}
 | 
			
		||||
.card .entity-list-item .entity-list-item:hover {
 | 
			
		||||
  background-color: #EEEEEE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item-children {
 | 
			
		||||
  padding: $-m;
 | 
			
		||||
  > div {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    padding: $-xs 0;
 | 
			
		||||
    margin-top: -$-xs;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-chip {
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    height: 2.5em;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    display: block;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item-image {
 | 
			
		||||
  align-self: stretch;
 | 
			
		||||
  width: 140px;
 | 
			
		||||
  flex: none;
 | 
			
		||||
  background-size: cover;
 | 
			
		||||
  background-position: 50% 50%;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  margin-right: $-l;
 | 
			
		||||
 | 
			
		||||
  .svg-icon {
 | 
			
		||||
    color: #FFF;
 | 
			
		||||
    fill: #FFF;
 | 
			
		||||
    font-size: 1.66rem;
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: $-xs;
 | 
			
		||||
    left: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @include smaller-than($m) {
 | 
			
		||||
    width: 80px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.chapter > .entity-list-item-image {
 | 
			
		||||
  width: 60px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list.compact {
 | 
			
		||||
  font-size: 0.6em;
 | 
			
		||||
  font-size: 0.6 * $fs-m;
 | 
			
		||||
  h4, a {
 | 
			
		||||
    line-height: 1.2;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -331,6 +497,11 @@ ul.pagination {
 | 
			
		|||
  hr {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($m) {
 | 
			
		||||
    h4 {
 | 
			
		||||
      font-size: 1.666em;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container {
 | 
			
		||||
| 
						 | 
				
			
			@ -363,9 +534,8 @@ ul.pagination {
 | 
			
		|||
    color: #999;
 | 
			
		||||
    fill: #999;
 | 
			
		||||
  }
 | 
			
		||||
  li.padded {
 | 
			
		||||
    padding: $-xs $-m;
 | 
			
		||||
    line-height: 1.2;
 | 
			
		||||
  li.active a {
 | 
			
		||||
    font-weight: 600;
 | 
			
		||||
  }
 | 
			
		||||
  a, button {
 | 
			
		||||
    display: block;
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +566,10 @@ ul.pagination {
 | 
			
		|||
.featured-image-container {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  background: #F2F2F2;
 | 
			
		||||
  min-height: 140px;
 | 
			
		||||
  background-size: cover;
 | 
			
		||||
  background-position: 50% 50%;
 | 
			
		||||
  transition: opacity ease-in-out 240ms;
 | 
			
		||||
  a {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -405,11 +578,46 @@ ul.pagination {
 | 
			
		|||
    width: 100%;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    transition: all .5s ease-in-out;
 | 
			
		||||
  }
 | 
			
		||||
  img:hover {
 | 
			
		||||
    transform: scale(1.15);
 | 
			
		||||
    opacity: .5;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.featured-image-container-wrap {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  .svg-icon {
 | 
			
		||||
    color: #FFF;
 | 
			
		||||
    fill: #FFF;
 | 
			
		||||
    font-size: 2rem;
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 10px;
 | 
			
		||||
    left: 6px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.grid-card:hover .featured-image-container {
 | 
			
		||||
  opacity: .5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.action-link-list {
 | 
			
		||||
  //padding: $-s 0;
 | 
			
		||||
}
 | 
			
		||||
.action-link {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  border: none;
 | 
			
		||||
  color: currentColor;
 | 
			
		||||
  padding: $-m 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.active-link-list {
 | 
			
		||||
  a {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    padding: $-s;
 | 
			
		||||
  }
 | 
			
		||||
  a:not(.active) {
 | 
			
		||||
    color: #444;
 | 
			
		||||
    fill: #444;
 | 
			
		||||
  }
 | 
			
		||||
  a:hover {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,12 +5,6 @@
 | 
			
		|||
@mixin larger-than($size) {
 | 
			
		||||
    @media screen and (min-width: $size) { @content; }
 | 
			
		||||
}
 | 
			
		||||
@mixin clearfix() {
 | 
			
		||||
  &:after {
 | 
			
		||||
    display: block;
 | 
			
		||||
    content: '';
 | 
			
		||||
    font-size: 0;
 | 
			
		||||
    clear: both;
 | 
			
		||||
    position: relative;
 | 
			
		||||
  }
 | 
			
		||||
@mixin between($min, $max) {
 | 
			
		||||
  @media screen and (min-width: $min) and (max-width: $max) { @content; }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,12 +3,12 @@
 | 
			
		|||
  flex-direction: column;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  .faded-small {
 | 
			
		||||
    height: auto;
 | 
			
		||||
  }
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
 | 
			
		||||
  .edit-area {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .mce-tinymce {
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,39 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  .page-edit-toolbar {
 | 
			
		||||
    overflow-x: scroll;
 | 
			
		||||
    overflow-y: visible;
 | 
			
		||||
    z-index: 4;
 | 
			
		||||
  }
 | 
			
		||||
  .page-edit-toolbar .grid.third {
 | 
			
		||||
    display: block;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    > div {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  .page-edit-toolbar #save-button {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    z-index: 30;
 | 
			
		||||
    background-color: #FFF;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    width: 42px;
 | 
			
		||||
    height: 42px;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    right: $-m;
 | 
			
		||||
    bottom: $-xs;
 | 
			
		||||
    box-shadow: $bs-med;
 | 
			
		||||
    span {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draft-notification {
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
  transform: scale(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -38,11 +71,7 @@
 | 
			
		|||
  width: 100%;
 | 
			
		||||
  max-width: 840px;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
  margin-top: $-xxl;
 | 
			
		||||
  overflow-wrap: break-word;
 | 
			
		||||
  &.flex {
 | 
			
		||||
    margin-top: $-m;
 | 
			
		||||
  }
 | 
			
		||||
  .align-left {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -248,13 +277,6 @@
 | 
			
		|||
    min-height: 0px;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
  }
 | 
			
		||||
  div[toolbox-tab-content] .padded {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
  }
 | 
			
		||||
  div[toolbox-tab-content] .padded.files {
 | 
			
		||||
	overflow-x: hidden;
 | 
			
		||||
  }
 | 
			
		||||
  h4 {
 | 
			
		||||
    font-size: 24px;
 | 
			
		||||
    margin: $-m 0 0 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -349,16 +371,10 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  border-top: 1px solid #DDD;
 | 
			
		||||
  margin-top: $-xl;
 | 
			
		||||
  margin-bottom: $-m;
 | 
			
		||||
  h5 {
 | 
			
		||||
    color: #888;
 | 
			
		||||
    font-weight: normal;
 | 
			
		||||
    margin-top: 0.5em;
 | 
			
		||||
  }
 | 
			
		||||
.comments-container h5 {
 | 
			
		||||
  color: #888;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  margin-top: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
 | 
			
		||||
| 
						 | 
				
			
			@ -370,4 +386,60 @@
 | 
			
		|||
  .mce-open {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item > span:first-child, .icon-list-item > span:first-child, .chapter-expansion > .icon {
 | 
			
		||||
  font-size: 0.8rem;
 | 
			
		||||
  width: 1.88em;
 | 
			
		||||
  height: 1.88em;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 1em;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  svg {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
  &:after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    background-color: currentColor;
 | 
			
		||||
    opacity: 0.2;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-chip {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  padding: $-xs $-s;
 | 
			
		||||
  fill: currentColor;
 | 
			
		||||
  opacity: 0.85;
 | 
			
		||||
  transition: opacity ease-in-out 120ms;
 | 
			
		||||
  &:after {
 | 
			
		||||
    content: '';
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    background-color: currentColor;
 | 
			
		||||
    opacity: 0.15;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  &:hover {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
// Here we generate spacing utility classes for our sizes for all box sides and axis.
 | 
			
		||||
// These will output to classes like .px-m (Padding on x-axis, medium size) or .mr-l (Margin right, large size)
 | 
			
		||||
 | 
			
		||||
@mixin spacing($prop, $propLetter) {
 | 
			
		||||
  @each $sizeLetter, $size in $spacing {
 | 
			
		||||
    .#{$propLetter}-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}x-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-left: $size !important;
 | 
			
		||||
      #{$prop}-right: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}y-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-top: $size !important;
 | 
			
		||||
      #{$prop}-bottom: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}t-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-top: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}r-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-right: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}b-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-bottom: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
    .#{$propLetter}l-#{$sizeLetter} {
 | 
			
		||||
      #{$prop}-left: $size !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@include spacing('margin', 'm')
 | 
			
		||||
@include spacing('padding', 'p')
 | 
			
		||||
| 
						 | 
				
			
			@ -19,13 +19,13 @@ table {
 | 
			
		|||
 | 
			
		||||
table.table {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  tr {
 | 
			
		||||
    border-bottom: 1px solid #DDD;
 | 
			
		||||
  tr td, tr th {
 | 
			
		||||
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
 | 
			
		||||
  }
 | 
			
		||||
  th, td {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    border: none;
 | 
			
		||||
    padding: $-xs $-xs;
 | 
			
		||||
    padding: $-s $-s;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +44,9 @@ table.table {
 | 
			
		|||
  td.actions {
 | 
			
		||||
    overflow: visible;
 | 
			
		||||
  }
 | 
			
		||||
  a {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.no-style {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ h1, h2, h3, h4, h5, h6 {
 | 
			
		|||
  font-weight: 400;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  display: block;
 | 
			
		||||
  color: #555;
 | 
			
		||||
  color: #222;
 | 
			
		||||
  .subheader {
 | 
			
		||||
    font-size: 0.5em;
 | 
			
		||||
    line-height: 1em;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,10 +79,18 @@ h5, h6 {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list-heading {
 | 
			
		||||
  font-size: 2rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h2.list-heading {
 | 
			
		||||
  font-size: 1.333rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Link styling
 | 
			
		||||
 */
 | 
			
		||||
a, .link {
 | 
			
		||||
a {
 | 
			
		||||
  color: $primary;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
| 
						 | 
				
			
			@ -141,11 +149,8 @@ em, i, .italic {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
small, p.small, span.small, .text-small {
 | 
			
		||||
  font-size: 0.8em;
 | 
			
		||||
  color: lighten($text-dark, 20%);
 | 
			
		||||
  small, p.small, span.small, .text-small {
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
  }
 | 
			
		||||
  font-size: 0.75rem;
 | 
			
		||||
  color: lighten($text-dark, 10%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sup, .superscript {
 | 
			
		||||
| 
						 | 
				
			
			@ -233,106 +238,6 @@ pre code {
 | 
			
		|||
  display: block;
 | 
			
		||||
  line-height: 1.6;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
 * Text colors
 | 
			
		||||
 */
 | 
			
		||||
p.pos, p .pos, span.pos, .text-pos {
 | 
			
		||||
  color: $positive;
 | 
			
		||||
  fill: $positive;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $positive;
 | 
			
		||||
    fill: $positive;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p.neg, p .neg, span.neg, .text-neg {
 | 
			
		||||
  color: $negative;
 | 
			
		||||
  fill: $negative;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $negative;
 | 
			
		||||
    fill: $negative;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p.muted, p .muted, span.muted, .text-muted {
 | 
			
		||||
	color: lighten($text-dark, 26%);
 | 
			
		||||
	fill: lighten($text-dark, 26%);
 | 
			
		||||
    &.small, .small {
 | 
			
		||||
      color: lighten($text-dark, 32%);
 | 
			
		||||
      fill: lighten($text-dark, 32%);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p.primary, p .primary, span.primary, .text-primary {
 | 
			
		||||
	color: $primary;
 | 
			
		||||
	fill: $primary;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $primary;
 | 
			
		||||
    fill: $primary;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p.secondary, p .secondary, span.secondary, .text-secondary {
 | 
			
		||||
	color: $secondary;
 | 
			
		||||
	fill: $secondary;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $secondary;
 | 
			
		||||
    fill: $secondary;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-bookshelf {
 | 
			
		||||
  color: $color-bookshelf;
 | 
			
		||||
  fill: $color-bookshelf;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $color-bookshelf;
 | 
			
		||||
    fill: $color-bookshelf;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.text-book {
 | 
			
		||||
  color: $color-book;
 | 
			
		||||
  fill: $color-book;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $color-book;
 | 
			
		||||
    fill: $color-book;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.text-page {
 | 
			
		||||
  color: $color-page;
 | 
			
		||||
  fill: $color-page;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $color-page;
 | 
			
		||||
    fill: $color-page;
 | 
			
		||||
  }
 | 
			
		||||
  &.draft {
 | 
			
		||||
    color: $color-page-draft;
 | 
			
		||||
    fill: $color-page-draft;
 | 
			
		||||
  }
 | 
			
		||||
  &.draft:hover {
 | 
			
		||||
    color: $color-page-draft;
 | 
			
		||||
    fill: $color-page-draft;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.text-chapter {
 | 
			
		||||
  color: $color-chapter;
 | 
			
		||||
  fill: $color-chapter;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $color-chapter;
 | 
			
		||||
    fill: $color-chapter;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.faded .text-book:hover {
 | 
			
		||||
  color: $color-book !important;
 | 
			
		||||
  fill: $color-book !important;
 | 
			
		||||
}
 | 
			
		||||
.faded .text-chapter:hover {
 | 
			
		||||
  color: $color-chapter !important;
 | 
			
		||||
  fill: $color-chapter !important;
 | 
			
		||||
}
 | 
			
		||||
.faded .text-page:hover {
 | 
			
		||||
  color: $color-page !important;
 | 
			
		||||
  fill: $color-page !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.highlight {
 | 
			
		||||
  //background-color: rgba($primary, 0.2);
 | 
			
		||||
| 
						 | 
				
			
			@ -435,10 +340,6 @@ span.sep {
 | 
			
		|||
/**
 | 
			
		||||
  * Icons
 | 
			
		||||
  */
 | 
			
		||||
i {
 | 
			
		||||
  padding-right: $-xs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.svg-icon {
 | 
			
		||||
  width: 1em;
 | 
			
		||||
  height: 1em;
 | 
			
		||||
| 
						 | 
				
			
			@ -446,5 +347,6 @@ i {
 | 
			
		|||
  position: relative;
 | 
			
		||||
  bottom: -0.105em;
 | 
			
		||||
  margin-right: $-xs;
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,13 @@
 | 
			
		|||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@include smaller-than($l) {
 | 
			
		||||
  .mce-container-body.mce-flow-layout {
 | 
			
		||||
    overflow-x: scroll;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.edit-area.flex > div > .mce-tinymce.mce-container.mce-panel {
 | 
			
		||||
  flex: 1 1 auto;
 | 
			
		||||
  display: flex !important;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,12 @@
 | 
			
		|||
// Variables
 | 
			
		||||
///////////////
 | 
			
		||||
 | 
			
		||||
// Sizes
 | 
			
		||||
$max-width: 1400px;
 | 
			
		||||
 | 
			
		||||
// Screen breakpoints
 | 
			
		||||
$xxl: 1400px;
 | 
			
		||||
$xl: 1100px;
 | 
			
		||||
$ipad-width: 1028px; // Is actually 1024 but we go over to ensure functionality.
 | 
			
		||||
$l: 1000px;
 | 
			
		||||
$m: 800px;
 | 
			
		||||
$m: 880px;
 | 
			
		||||
$s: 600px;
 | 
			
		||||
$xs: 400px;
 | 
			
		||||
$xxs: 360px;
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +14,9 @@ $screen-lg: 1200px;
 | 
			
		|||
$screen-md: 992px;
 | 
			
		||||
$screen-sm: 768px;
 | 
			
		||||
 | 
			
		||||
// List of screen sizes
 | 
			
		||||
$screen-sizes: (('xxs', $xxs), ('xs', $xs), ('s', $s), ('m', $m), ('l', $l), ('xl', $xl));
 | 
			
		||||
 | 
			
		||||
// Spacing (Margins+Padding)
 | 
			
		||||
$-xxxl: 64px;
 | 
			
		||||
$-xxl: 48px;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +27,9 @@ $-s: 12px;
 | 
			
		|||
$-xs: 6px;
 | 
			
		||||
$-xxs: 3px;
 | 
			
		||||
 | 
			
		||||
// List of our spacing sizes
 | 
			
		||||
$spacing: (('none', 0), ('xxs', $-xxs), ('xs', $-xs), ('s', $-s), ('m', $-m), ('l', $-l), ('xl', $-xl), ('xxl', $-xxl));
 | 
			
		||||
 | 
			
		||||
// Fonts
 | 
			
		||||
$text: -apple-system, BlinkMacSystemFont,
 | 
			
		||||
"Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell",
 | 
			
		||||
| 
						 | 
				
			
			@ -33,8 +37,8 @@ $text: -apple-system, BlinkMacSystemFont,
 | 
			
		|||
sans-serif;
 | 
			
		||||
$mono: "Lucida Console", "DejaVu Sans Mono", "Ubunto Mono", Monaco, monospace;
 | 
			
		||||
$heading: $text;
 | 
			
		||||
$fs-m: 15px;
 | 
			
		||||
$fs-s: 14px;
 | 
			
		||||
$fs-m: 14px;
 | 
			
		||||
$fs-s: 12px;
 | 
			
		||||
 | 
			
		||||
// Colours
 | 
			
		||||
$primary: #0288D1;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +53,7 @@ $primary-faded: rgba(21, 101, 192, 0.15);
 | 
			
		|||
// Item Colors
 | 
			
		||||
$color-bookshelf: #af5a5a;
 | 
			
		||||
$color-book: #009688;
 | 
			
		||||
$color-chapter: #ef7c3c;
 | 
			
		||||
$color-chapter: #d7804a;
 | 
			
		||||
$color-page: $primary;
 | 
			
		||||
$color-page-draft: #9A60DA;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,5 +64,5 @@ $text-light: #EEE;
 | 
			
		|||
// Shadows
 | 
			
		||||
$bs-light: 0 0 4px 1px #CCC;
 | 
			
		||||
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
 | 
			
		||||
$bs-card: 0 1px 3px 1px rgba(76, 76, 76, 0.26), 0 1px 12px 0px rgba(76, 76, 76, 0.2);
 | 
			
		||||
$bs-card: 0 1px 6px -1px rgba(0, 0, 0, 0.1);
 | 
			
		||||
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
@import "variables";
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "spacing";
 | 
			
		||||
@import "html";
 | 
			
		||||
@import "text";
 | 
			
		||||
@import "grid";
 | 
			
		||||
@import "layout";
 | 
			
		||||
@import "blocks";
 | 
			
		||||
@import "forms";
 | 
			
		||||
@import "tables";
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +13,9 @@
 | 
			
		|||
 | 
			
		||||
body {
 | 
			
		||||
  font-family: 'DejaVu Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +23,10 @@ table {
 | 
			
		|||
  border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-content {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Prevent code block overflow on export
 | 
			
		||||
pre {
 | 
			
		||||
  padding-left: 12px;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,6 @@ body {
 | 
			
		|||
  font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.faded-small {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-content {
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
@import "reset";
 | 
			
		||||
@import "variables";
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "spacing";
 | 
			
		||||
@import "html";
 | 
			
		||||
@import "text";
 | 
			
		||||
@import "grid";
 | 
			
		||||
@import "colors";
 | 
			
		||||
@import "layout";
 | 
			
		||||
@import "blocks";
 | 
			
		||||
@import "buttons";
 | 
			
		||||
@import "tables";
 | 
			
		||||
| 
						 | 
				
			
			@ -94,17 +96,6 @@ $loadingSize: 10px;
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Search results
 | 
			
		||||
.search-results > h3 a {
 | 
			
		||||
  font-size: 0.66em;
 | 
			
		||||
  color: $primary;
 | 
			
		||||
  padding-left: $-m;
 | 
			
		||||
  i {
 | 
			
		||||
    padding-right: $-s;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Back to top link
 | 
			
		||||
$btt-size: 40px;
 | 
			
		||||
[back-to-top] {
 | 
			
		||||
| 
						 | 
				
			
			@ -186,22 +177,28 @@ $btt-size: 40px;
 | 
			
		|||
    overflow-y: scroll;
 | 
			
		||||
    height: 400px;
 | 
			
		||||
    background-color: #EEEEEE;
 | 
			
		||||
    margin-right: 0;
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item {
 | 
			
		||||
    background-color: #FFF;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item p {
 | 
			
		||||
    margin-bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list-item.selected {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.15) !important;
 | 
			
		||||
  }
 | 
			
		||||
  .loading {
 | 
			
		||||
    height: 400px;
 | 
			
		||||
    padding-top: $-l;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list > p {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    padding-top: $-l;
 | 
			
		||||
    font-size: 1.333em;
 | 
			
		||||
  }
 | 
			
		||||
  .entity-list > div {
 | 
			
		||||
    padding-left: $-m;
 | 
			
		||||
    padding-right: $-m;
 | 
			
		||||
    background-color: #FFF;
 | 
			
		||||
    transition: all ease-in-out 120ms;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  .entity-selector-add button {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border: 0;
 | 
			
		||||
    border-top: 1px solid #DDD;
 | 
			
		||||
  }
 | 
			
		||||
  &.compact {
 | 
			
		||||
    font-size: 10px;
 | 
			
		||||
| 
						 | 
				
			
			@ -211,12 +208,6 @@ $btt-size: 40px;
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list-item.selected {
 | 
			
		||||
  h3, i, p ,a, span {
 | 
			
		||||
    color: #EEE;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.scroll-box {
 | 
			
		||||
  max-height: 250px;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
| 
						 | 
				
			
			@ -254,3 +245,39 @@ $btt-size: 40px;
 | 
			
		|||
  height:100%;
 | 
			
		||||
  z-index: 150;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list-sort-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  form {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
  }
 | 
			
		||||
  .list-sort {
 | 
			
		||||
    display: inline-grid;
 | 
			
		||||
    margin-left: $-s;
 | 
			
		||||
    grid-template-columns: 120px 40px;
 | 
			
		||||
    border: 2px solid #DDD;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
  }
 | 
			
		||||
  .list-sort-label {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    color: #888;
 | 
			
		||||
  }
 | 
			
		||||
  .list-sort-type {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  }
 | 
			
		||||
  .list-sort-type, .list-sort-dir {
 | 
			
		||||
    padding: $-xs $-s;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
  .list-sort-dir {
 | 
			
		||||
    border-left: 2px solid #DDD;
 | 
			
		||||
    fill: #888;
 | 
			
		||||
    .svg-icon {
 | 
			
		||||
      transition: transform ease-in-out 120ms;
 | 
			
		||||
    }
 | 
			
		||||
    &:hover .svg-icon {
 | 
			
		||||
      transform: rotate(180deg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ return [
 | 
			
		|||
    'save' => 'Save',
 | 
			
		||||
    'continue' => 'Continue',
 | 
			
		||||
    'select' => 'Select',
 | 
			
		||||
    'toggle_all' => 'Toggle All',
 | 
			
		||||
    'more' => 'More',
 | 
			
		||||
 | 
			
		||||
    // Form Labels
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,7 @@ return [
 | 
			
		|||
    // Actions
 | 
			
		||||
    'actions' => 'Actions',
 | 
			
		||||
    'view' => 'View',
 | 
			
		||||
    'view_all' => 'View All',
 | 
			
		||||
    'create' => 'Create',
 | 
			
		||||
    'update' => 'Update',
 | 
			
		||||
    'edit' => 'Edit',
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +39,11 @@ return [
 | 
			
		|||
    'remove' => 'Remove',
 | 
			
		||||
    'add' => 'Add',
 | 
			
		||||
 | 
			
		||||
    // Sort Options
 | 
			
		||||
    'sort_name' => 'Name',
 | 
			
		||||
    'sort_created_at' => 'Created Date',
 | 
			
		||||
    'sort_updated_at' => 'Updated Date',
 | 
			
		||||
 | 
			
		||||
    // Misc
 | 
			
		||||
    'deleted_user' => 'Deleted User',
 | 
			
		||||
    'no_activity' => 'No activity to show',
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +60,11 @@ return [
 | 
			
		|||
    'view_profile' => 'View Profile',
 | 
			
		||||
    'edit_profile' => 'Edit Profile',
 | 
			
		||||
 | 
			
		||||
    // Layout tabs
 | 
			
		||||
    'tab_info' => 'Info',
 | 
			
		||||
    'tab_content' => 'Content',
 | 
			
		||||
 | 
			
		||||
    // Email Content
 | 
			
		||||
    'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:',
 | 
			
		||||
    'email_rights' => 'All rights reserved',
 | 
			
		||||
];
 | 
			
		||||
];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ return [
 | 
			
		|||
    'recently_updated_pages' => 'Recently Updated Pages',
 | 
			
		||||
    'recently_created_chapters' => 'Recently Created Chapters',
 | 
			
		||||
    'recently_created_books' => 'Recently Created Books',
 | 
			
		||||
    'recently_created_shelves' => 'Recently Created Shelves',
 | 
			
		||||
    'recently_update' => 'Recently Updated',
 | 
			
		||||
    'recently_viewed' => 'Recently Viewed',
 | 
			
		||||
    'recent_activity' => 'Recent Activity',
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +68,7 @@ return [
 | 
			
		|||
    // Shelves
 | 
			
		||||
    'shelf' => 'Shelf',
 | 
			
		||||
    'shelves' => 'Shelves',
 | 
			
		||||
    'x_shelves' => ':count Shelf|:count Shelves',
 | 
			
		||||
    'shelves_long' => 'Bookshelves',
 | 
			
		||||
    'shelves_empty' => 'No shelves have been created',
 | 
			
		||||
    'shelves_create' => 'Create New Shelf',
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +119,6 @@ return [
 | 
			
		|||
    'books_permissions_updated' => 'Book Permissions Updated',
 | 
			
		||||
    'books_empty_contents' => 'No pages or chapters have been created for this book.',
 | 
			
		||||
    'books_empty_create_page' => 'Create a new page',
 | 
			
		||||
    'books_empty_or' => 'or',
 | 
			
		||||
    'books_empty_sort_current_book' => 'Sort the current book',
 | 
			
		||||
    'books_empty_add_chapter' => 'Add a chapter',
 | 
			
		||||
    'books_permissions_active' => 'Book Permissions Active',
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +126,11 @@ return [
 | 
			
		|||
    'books_navigation' => 'Book Navigation',
 | 
			
		||||
    'books_sort' => 'Sort Book Contents',
 | 
			
		||||
    'books_sort_named' => 'Sort Book :bookName',
 | 
			
		||||
    'books_sort_name' => 'Sort by Name',
 | 
			
		||||
    'books_sort_created' => 'Sort by Created Date',
 | 
			
		||||
    'books_sort_updated' => 'Sort by Updated Date',
 | 
			
		||||
    'books_sort_chapters_first' => 'Chapters First',
 | 
			
		||||
    'books_sort_chapters_last' => 'Chapters Last',
 | 
			
		||||
    'books_sort_show_other' => 'Show Other Books',
 | 
			
		||||
    'books_sort_save' => 'Save New Order',
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +208,8 @@ return [
 | 
			
		|||
    'pages_revisions_created_by' => 'Created By',
 | 
			
		||||
    'pages_revisions_date' => 'Revision Date',
 | 
			
		||||
    'pages_revisions_number' => '#',
 | 
			
		||||
    'pages_revisions_numbered' => 'Revision #:id',
 | 
			
		||||
    'pages_revisions_numbered_changes' => 'Revision #:id Changes',
 | 
			
		||||
    'pages_revisions_changelog' => 'Changelog',
 | 
			
		||||
    'pages_revisions_changes' => 'Changes',
 | 
			
		||||
    'pages_revisions_current' => 'Current Version',
 | 
			
		||||
| 
						 | 
				
			
			@ -267,6 +275,7 @@ return [
 | 
			
		|||
    'profile_not_created_pages' => ':userName has not created any pages',
 | 
			
		||||
    'profile_not_created_chapters' => ':userName has not created any chapters',
 | 
			
		||||
    'profile_not_created_books' => ':userName has not created any books',
 | 
			
		||||
    'profile_not_created_shelves' => ':userName has not created any shelves',
 | 
			
		||||
 | 
			
		||||
    // Comments
 | 
			
		||||
    'comment' => 'Comment',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,34 +12,44 @@ return [
 | 
			
		|||
    'settings_save_success' => 'Settings saved',
 | 
			
		||||
 | 
			
		||||
    // App Settings
 | 
			
		||||
    'app_settings' => 'App Settings',
 | 
			
		||||
    'app_name' => 'Application name',
 | 
			
		||||
    'app_name_desc' => 'This name is shown in the header and any emails.',
 | 
			
		||||
    'app_name_header' => 'Show Application name in header?',
 | 
			
		||||
    'app_customization' => 'Customization',
 | 
			
		||||
    'app_features_security' => 'Features & Security',
 | 
			
		||||
    'app_name' => 'Application Name',
 | 
			
		||||
    'app_name_desc' => 'This name is shown in the header and in any system-sent emails.',
 | 
			
		||||
    'app_name_header' => 'Show name in header',
 | 
			
		||||
    'app_public_access' => 'Public Access',
 | 
			
		||||
    'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.',
 | 
			
		||||
    'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.',
 | 
			
		||||
    'app_public_access_toggle' => 'Allow public access',
 | 
			
		||||
    'app_public_viewing' => 'Allow public viewing?',
 | 
			
		||||
    'app_secure_images' => 'Enable higher security image uploads?',
 | 
			
		||||
    'app_secure_images' => 'Higher Security Image Uploads',
 | 
			
		||||
    'app_secure_images_toggle' => 'Enable higher security image uploads',
 | 
			
		||||
    'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.',
 | 
			
		||||
    'app_editor' => 'Page editor',
 | 
			
		||||
    'app_editor' => 'Page Editor',
 | 
			
		||||
    'app_editor_desc' => 'Select which editor will be used by all users to edit pages.',
 | 
			
		||||
    'app_custom_html' => 'Custom HTML head content',
 | 
			
		||||
    'app_custom_html' => 'Custom HTML Head Content',
 | 
			
		||||
    'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the <head> section of every page. This is handy for overriding styles or adding analytics code.',
 | 
			
		||||
    'app_logo' => 'Application logo',
 | 
			
		||||
    'app_logo' => 'Application Logo',
 | 
			
		||||
    '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' => '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 view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
 | 
			
		||||
    'app_homepage_select' => 'Select a page',
 | 
			
		||||
    'app_disable_comments' => 'Disable comments',
 | 
			
		||||
    'app_disable_comments_desc' => 'Disable comments across all pages in the application. Existing comments are not shown.',
 | 
			
		||||
    'app_disable_comments' => 'Disable Comments',
 | 
			
		||||
    'app_disable_comments_toggle' => 'Disable comments',
 | 
			
		||||
    'app_disable_comments_desc' => 'Disables comments across all pages in the application. <br> Existing comments are not shown.',
 | 
			
		||||
 | 
			
		||||
    // Registration Settings
 | 
			
		||||
    'reg_settings' => 'Registration Settings',
 | 
			
		||||
    'reg_allow' => 'Allow registration?',
 | 
			
		||||
    'reg_settings' => 'Registration',
 | 
			
		||||
    'reg_enable' => 'Enable Registration',
 | 
			
		||||
    'reg_enable_toggle' => 'Enable registration',
 | 
			
		||||
    'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.',
 | 
			
		||||
    'reg_default_role' => 'Default user role after registration',
 | 
			
		||||
    'reg_confirm_email' => 'Require email confirmation?',
 | 
			
		||||
    'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and the below value will be ignored.',
 | 
			
		||||
    'reg_confirm_restrict_domain' => 'Restrict registration to domain',
 | 
			
		||||
    'reg_email_confirmation' => 'Email Confirmation',
 | 
			
		||||
    'reg_email_confirmation_toggle' => 'Require email confirmation',
 | 
			
		||||
    'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.',
 | 
			
		||||
    'reg_confirm_restrict_domain' => 'Domain Restriction',
 | 
			
		||||
    'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
 | 
			
		||||
    'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,9 +101,16 @@ return [
 | 
			
		|||
    'user_profile' => 'User Profile',
 | 
			
		||||
    'users_add_new' => 'Add New User',
 | 
			
		||||
    'users_search' => 'Search Users',
 | 
			
		||||
    'users_details' => 'User Details',
 | 
			
		||||
    'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.',
 | 
			
		||||
    'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.',
 | 
			
		||||
    'users_role' => 'User Roles',
 | 
			
		||||
    'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.',
 | 
			
		||||
    'users_password' => 'User Password',
 | 
			
		||||
    'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 5 characters long.',
 | 
			
		||||
    'users_external_auth_id' => 'External Authentication ID',
 | 
			
		||||
    'users_password_warning' => 'Only fill the below if you would like to change your password:',
 | 
			
		||||
    'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.',
 | 
			
		||||
    'users_password_warning' => 'Only fill the below if you would like to change your password.',
 | 
			
		||||
    'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.',
 | 
			
		||||
    'users_delete' => 'Delete User',
 | 
			
		||||
    'users_delete_named' => 'Delete user :userName',
 | 
			
		||||
| 
						 | 
				
			
			@ -104,8 +121,9 @@ return [
 | 
			
		|||
    'users_edit_profile' => 'Edit Profile',
 | 
			
		||||
    'users_edit_success' => 'User successfully updated',
 | 
			
		||||
    'users_avatar' => 'User Avatar',
 | 
			
		||||
    'users_avatar_desc' => 'This image should be approx 256px square.',
 | 
			
		||||
    'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.',
 | 
			
		||||
    'users_preferred_language' => 'Preferred Language',
 | 
			
		||||
    'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.',
 | 
			
		||||
    'users_social_accounts' => 'Social Accounts',
 | 
			
		||||
    'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.',
 | 
			
		||||
    'users_social_connect' => 'Connect Account',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
<div class="form-group">
 | 
			
		||||
    <label for="username">{{ trans('auth.username') }}</label>
 | 
			
		||||
    @include('form/text', ['name' => 'username', 'tabindex' => 1])
 | 
			
		||||
    @include('form.text', ['name' => 'username', 'tabindex' => 1])
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@if(session('request-email', false) === true)
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
        <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
        @include('form/text', ['name' => 'email', 'tabindex' => 1])
 | 
			
		||||
        @include('form.text', ['name' => 'email', 'tabindex' => 1])
 | 
			
		||||
        <span class="text-neg">
 | 
			
		||||
            {{ trans('auth.ldap_email_hint') }}
 | 
			
		||||
        </span>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,5 +15,5 @@
 | 
			
		|||
 | 
			
		||||
<div class="form-group">
 | 
			
		||||
    <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
    @include('form/password', ['name' => 'password', 'tabindex' => 2])
 | 
			
		||||
    @include('form.password', ['name' => 'password', 'tabindex' => 2])
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
<div class="form-group">
 | 
			
		||||
    <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
    @include('form/text', ['name' => 'email', 'tabindex' => 1])
 | 
			
		||||
    @include('form.text', ['name' => 'email', 'tabindex' => 1])
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="form-group">
 | 
			
		||||
    <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
    @include('form/password', ['name' => 'password', 'tabindex' => 2])
 | 
			
		||||
    <span class="block small"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
 | 
			
		||||
    @include('form.password', ['name' => 'password', 'tabindex' => 1])
 | 
			
		||||
    <span class="block small mt-s"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,44 +1,48 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
 | 
			
		||||
@section('header-buttons')
 | 
			
		||||
    @if(setting('registration-enabled', false))
 | 
			
		||||
        <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
 | 
			
		||||
    @endif
 | 
			
		||||
@stop
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
        <div class="card center-box">
 | 
			
		||||
            <h3>@icon('login') {{ title_case(trans('auth.log_in')) }}</h3>
 | 
			
		||||
    <div class="container very-small">
 | 
			
		||||
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <form action="{{ baseUrl("/login") }}" method="POST" id="login-form">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
        <div class="my-l"> </div>
 | 
			
		||||
 | 
			
		||||
                    @include('auth/forms/login/' . $authMethod)
 | 
			
		||||
        <div class="card content-wrap">
 | 
			
		||||
            <h1 class="list-heading">{{ title_case(trans('auth.log_in')) }}</h1>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="remember" class="inline">{{ trans('auth.remember_me') }}</label>
 | 
			
		||||
                        <input type="checkbox" id="remember" name="remember"  class="toggle-switch-checkbox">
 | 
			
		||||
                        <label for="remember" class="toggle-switch"></label>
 | 
			
		||||
            <form action="{{ baseUrl("/login") }}" method="POST" id="login-form" class="mt-l">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
 | 
			
		||||
                <div class="stretch-inputs">
 | 
			
		||||
                    @include('auth.forms.login.' . $authMethod)
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="grid half collapse-xs gap-xl v-center">
 | 
			
		||||
                    <div class="text-left ml-xxs">
 | 
			
		||||
                        @include('components.custom-checkbox', [
 | 
			
		||||
                            'name' => 'remember',
 | 
			
		||||
                            'checked' => false,
 | 
			
		||||
                            'value' => 'on',
 | 
			
		||||
                            'label' => trans('auth.remember_me'),
 | 
			
		||||
                        ])
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="from-group">
 | 
			
		||||
                        <button class="button block pos" tabindex="3">@icon('login') {{ title_case(trans('auth.log_in')) }}</button>
 | 
			
		||||
                    <div class="text-right">
 | 
			
		||||
                        <button class="button primary" tabindex="3">{{ title_case(trans('auth.log_in')) }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                @if(count($socialDrivers) > 0)
 | 
			
		||||
                    <hr class="margin-top">
 | 
			
		||||
                    @foreach($socialDrivers as $driver => $name)
 | 
			
		||||
                        <a id="social-login-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/login/service/" . $driver) }}">
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
            @if(count($socialDrivers) > 0)
 | 
			
		||||
                <hr class="my-l">
 | 
			
		||||
                @foreach($socialDrivers as $driver => $name)
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <a id="social-login-{{$driver}}" class="button outline block svg" href="{{ baseUrl("/login/service/" . $driver) }}">
 | 
			
		||||
                            @icon('auth/' . $driver)
 | 
			
		||||
                            {{ trans('auth.log_in_with', ['socialDriver' => $name]) }}
 | 
			
		||||
                        </a>
 | 
			
		||||
                    @endforeach
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                @endforeach
 | 
			
		||||
            @endif
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,37 +1,25 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
 | 
			
		||||
@section('header-buttons')
 | 
			
		||||
    <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
 | 
			
		||||
    @if(setting('registration-enabled'))
 | 
			
		||||
        <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
 | 
			
		||||
    @endif
 | 
			
		||||
@stop
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
    <div class="container very-small mt-xl">
 | 
			
		||||
        <div class="card content-wrap auto-height">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('auth.reset_password') }}</h1>
 | 
			
		||||
 | 
			
		||||
            <p class="text-muted small">{{ trans('auth.reset_password_send_instructions') }}</p>
 | 
			
		||||
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
        <div class="card center-box">
 | 
			
		||||
            <h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
 | 
			
		||||
            <form action="{{ baseUrl("/password/email") }}" method="POST" class="stretch-inputs">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <p class="muted small">{{ trans('auth.reset_password_send_instructions') }}</p>
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                    @include('form.text', ['name' => 'email'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <form action="{{ baseUrl("/password/email") }}" method="POST">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                        @include('form/text', ['name' => 'email'])
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="from-group text-right">
 | 
			
		||||
                        <button class="button primary">{{ trans('auth.reset_password_send_button') }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
                <div class="from-group text-right mt-m">
 | 
			
		||||
                    <button class="button primary">{{ trans('auth.reset_password_send_button') }}</button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -1,43 +1,34 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
 | 
			
		||||
@section('header-buttons')
 | 
			
		||||
    <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
 | 
			
		||||
    @if(setting('registration-enabled'))
 | 
			
		||||
        <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
 | 
			
		||||
    @endif
 | 
			
		||||
@stop
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
        <div class="card center-box">
 | 
			
		||||
            <h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
 | 
			
		||||
    <div class="container very-small mt-xl">
 | 
			
		||||
        <div class="card content-wrap auto-height">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('auth.reset_password') }}</h1>
 | 
			
		||||
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <form action="{{ baseUrl("/password/reset") }}" method="POST">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
                    <input type="hidden" name="token" value="{{ $token }}">
 | 
			
		||||
            <form action="{{ baseUrl("/password/reset") }}" method="POST" class="stretch-inputs">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
                <input type="hidden" name="token" value="{{ $token }}">
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                        @include('form/text', ['name' => 'email'])
 | 
			
		||||
                    </div>
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                    @include('form.text', ['name' => 'email'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
                        @include('form/password', ['name' => 'password'])
 | 
			
		||||
                    </div>
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
                    @include('form.password', ['name' => 'password'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
 | 
			
		||||
                        @include('form/password', ['name' => 'password_confirmation'])
 | 
			
		||||
                    </div>
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
 | 
			
		||||
                    @include('form.password', ['name' => 'password_confirmation'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="from-group text-right">
 | 
			
		||||
                        <button class="button primary">{{ trans('auth.reset_password') }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
                <div class="from-group text-right mt-m">
 | 
			
		||||
                    <button class="button primary">{{ trans('auth.reset_password') }}</button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,11 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
 | 
			
		||||
@section('header-buttons')
 | 
			
		||||
    @if(!$signedIn)
 | 
			
		||||
        <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
 | 
			
		||||
    @endif
 | 
			
		||||
@stop
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
        <div class="card center-box">
 | 
			
		||||
            <h3>@icon('users') {{ trans('auth.register_thanks') }}</h3>
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
    <div class="container very-small mt-xl">
 | 
			
		||||
        <div class="card content-wrap auto-height">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('auth.register_thanks') }}</h1>
 | 
			
		||||
            <p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,50 +1,54 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
 | 
			
		||||
@section('header-buttons')
 | 
			
		||||
    <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
 | 
			
		||||
@stop
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
    <div class="container very-small">
 | 
			
		||||
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
        <div class="card center-box">
 | 
			
		||||
            <h3>@icon('new-user')  {{ title_case(trans('auth.sign_up')) }}</h3>
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <form action="{{ baseUrl("/register") }}" method="POST">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
        <div class="my-l"> </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="email">{{ trans('auth.name') }}</label>
 | 
			
		||||
                        @include('form/text', ['name' => 'name'])
 | 
			
		||||
        <div class="card content-wrap">
 | 
			
		||||
            <h1 class="list-heading">{{ title_case(trans('auth.sign_up')) }}</h1>
 | 
			
		||||
 | 
			
		||||
            <form action="{{ baseUrl("/register") }}" method="POST" class="mt-l stretch-inputs">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="email">{{ trans('auth.name') }}</label>
 | 
			
		||||
                    @include('form.text', ['name' => 'name'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                    @include('form.text', ['name' => 'email'])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
                    @include('form.password', ['name' => 'password', 'placeholder' => trans('auth.password_hint')])
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="grid half collapse-xs gap-xl v-center mt-m">
 | 
			
		||||
                    <div class="text-small">
 | 
			
		||||
                        <a href="{{ baseUrl('/login') }}">Already have an account?</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                        @include('form/text', ['name' => 'email'])
 | 
			
		||||
                    <div class="from-group text-right">
 | 
			
		||||
                        <button class="button primary">{{ trans('auth.create_account') }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="password">{{ trans('auth.password') }}</label>
 | 
			
		||||
                        @include('form/password', ['name' => 'password', 'placeholder' => trans('auth.password_hint')])
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="from-group">
 | 
			
		||||
                        <button class="button block pos">{{ trans('auth.create_account') }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
                @if(count($socialDrivers) > 0)
 | 
			
		||||
                    <hr class="margin-top">
 | 
			
		||||
                    @foreach($socialDrivers as $driver => $name)
 | 
			
		||||
                        <a id="social-register-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/register/service/" . $driver) }}">
 | 
			
		||||
            @if(count($socialDrivers) > 0)
 | 
			
		||||
                <hr class="my-l">
 | 
			
		||||
                @foreach($socialDrivers as $driver => $name)
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <a id="social-register-{{$driver}}" class="button block outline svg" href="{{ baseUrl("/register/service/" . $driver) }}">
 | 
			
		||||
                            @icon('auth/' . $driver)
 | 
			
		||||
                            {{ trans('auth.sign_up_with', ['socialDriver' => $name]) }}
 | 
			
		||||
                        </a>
 | 
			
		||||
                    @endforeach
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                @endforeach
 | 
			
		||||
            @endif
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,34 @@
 | 
			
		|||
@extends('public')
 | 
			
		||||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="container small">
 | 
			
		||||
        <p> </p>
 | 
			
		||||
        <div class="card">
 | 
			
		||||
            <h3>@icon('users') {{ trans('auth.email_not_confirmed') }}</h3>
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <p class="text-muted">{{ trans('auth.email_not_confirmed_text') }}<br>
 | 
			
		||||
                    {{ trans('auth.email_not_confirmed_click_link') }} <br>
 | 
			
		||||
                    {{ trans('auth.email_not_confirmed_resend') }}
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <form action="{{ baseUrl("/register/confirm/resend") }}" method="POST">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                        @if(auth()->check())
 | 
			
		||||
                            @include('form/text', ['name' => 'email', 'model' => auth()->user()])
 | 
			
		||||
                        @else
 | 
			
		||||
                            @include('form/text', ['name' => 'email'])
 | 
			
		||||
                        @endif
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <button type="submit" class="button pos">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    <div class="container very-small mt-xl">
 | 
			
		||||
        <div class="card content-wrap auto-height">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('auth.email_not_confirmed') }}</h1>
 | 
			
		||||
 | 
			
		||||
            <p>{{ trans('auth.email_not_confirmed_text') }}<br>
 | 
			
		||||
                {{ trans('auth.email_not_confirmed_click_link') }}
 | 
			
		||||
            </p>
 | 
			
		||||
            <p>
 | 
			
		||||
                {{ trans('auth.email_not_confirmed_resend') }}
 | 
			
		||||
            </p>
 | 
			
		||||
 | 
			
		||||
            <form action="{{ baseUrl("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                    <label for="email">{{ trans('auth.email') }}</label>
 | 
			
		||||
                    @if(auth()->check())
 | 
			
		||||
                        @include('form.text', ['name' => 'email', 'model' => auth()->user()])
 | 
			
		||||
                    @else
 | 
			
		||||
                        @include('form.text', ['name' => 'email'])
 | 
			
		||||
                    @endif
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group text-right mt-m">
 | 
			
		||||
                    <button type="submit" class="button primary">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,75 +17,29 @@
 | 
			
		|||
    <script src="{{ baseUrl('/translations') }}"></script>
 | 
			
		||||
 | 
			
		||||
    @yield('head')
 | 
			
		||||
 | 
			
		||||
    @include('partials/custom-styles')
 | 
			
		||||
 | 
			
		||||
    @include('partials.custom-styles')
 | 
			
		||||
    @include('partials.custom-head')
 | 
			
		||||
 | 
			
		||||
    @stack('head')
 | 
			
		||||
</head>
 | 
			
		||||
<body class="@yield('body-class')" ng-app="bookStack">
 | 
			
		||||
<body class="@yield('body-class')">
 | 
			
		||||
 | 
			
		||||
    @include('partials/notifications')
 | 
			
		||||
 | 
			
		||||
    <header id="header">
 | 
			
		||||
        <div class="container fluid">
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-sm-4 col-md-3">
 | 
			
		||||
                    <a href="{{ baseUrl('/') }}" class="logo">
 | 
			
		||||
                        @if(setting('app-logo', '') !== 'none')
 | 
			
		||||
                            <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
 | 
			
		||||
                        @endif
 | 
			
		||||
                        @if (setting('app-name-header'))
 | 
			
		||||
                            <span class="logo-text">{{ setting('app-name') }}</span>
 | 
			
		||||
                        @endif
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-8 col-md-9">
 | 
			
		||||
                    <div class="float right">
 | 
			
		||||
                        <div class="header-search">
 | 
			
		||||
                            <form action="{{ baseUrl('/search') }}" method="GET" class="search-box">
 | 
			
		||||
                                <button id="header-search-box-button" type="submit">@icon('search') </button>
 | 
			
		||||
                                <input id="header-search-box-input" type="text" name="term" tabindex="2" placeholder="{{ trans('common.search') }}" value="{{ isset($searchTerm) ? $searchTerm : '' }}">
 | 
			
		||||
                            </form>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="links text-center">
 | 
			
		||||
                            @if(userCanOnAny('view', \BookStack\Entities\Bookshelf::class) || userCan('bookshelf-view-own'))
 | 
			
		||||
                                <a href="{{ baseUrl('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            <a href="{{ baseUrl('/books') }}">@icon('book'){{ trans('entities.books') }}</a>
 | 
			
		||||
                            @if(signedInUser() && userCan('settings-manage'))
 | 
			
		||||
                                <a href="{{ baseUrl('/settings') }}">@icon('settings'){{ trans('settings.settings') }}</a>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            @if(signedInUser() && userCan('users-manage') && !userCan('settings-manage'))
 | 
			
		||||
                                <a href="{{ baseUrl('/settings/users') }}">@icon('users'){{ trans('settings.users') }}</a>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            @if(!signedInUser())
 | 
			
		||||
                                @if(setting('registration-enabled', false))
 | 
			
		||||
                                    <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
 | 
			
		||||
                                @endif
 | 
			
		||||
                                <a href="{{ baseUrl('/login') }}">@icon('login') {{ trans('auth.log_in') }}</a>
 | 
			
		||||
                            @endif
 | 
			
		||||
                        </div>
 | 
			
		||||
                        @if(signedInUser())
 | 
			
		||||
                            @include('partials._header-dropdown', ['currentUser' => user()])
 | 
			
		||||
                        @endif
 | 
			
		||||
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </header>
 | 
			
		||||
    @include('partials.notifications')
 | 
			
		||||
    @include('common.header')
 | 
			
		||||
 | 
			
		||||
    <section id="content" class="block">
 | 
			
		||||
        @yield('content')
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <div back-to-top>
 | 
			
		||||
    <div back-to-top class="primary-background">
 | 
			
		||||
        <div class="inner">
 | 
			
		||||
            @icon('chevron-up') <span>{{ trans('common.back_to_top') }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@yield('bottom')
 | 
			
		||||
<script src="{{ versioned_asset('dist/app.js') }}"></script>
 | 
			
		||||
@yield('scripts')
 | 
			
		||||
 | 
			
		||||
    @yield('bottom')
 | 
			
		||||
    <script src="{{ versioned_asset('dist/app.js') }}"></script>
 | 
			
		||||
    @yield('scripts')
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +1,27 @@
 | 
			
		|||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('toolbar')
 | 
			
		||||
    <div class="col-sm-8 faded">
 | 
			
		||||
        <div class="breadcrumbs">
 | 
			
		||||
            <a href="{{ baseUrl('/books') }}" class="text-button">@icon('book'){{ trans('entities.books') }}</a>
 | 
			
		||||
            <span class="sep">»</span>
 | 
			
		||||
            <a href="{{ baseUrl('/create-book') }}" class="text-button">@icon('add'){{ trans('entities.books_create') }}</a>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
    <div class="container small">
 | 
			
		||||
        <div class="my-s">
 | 
			
		||||
            @include('partials.breadcrumbs', ['crumbs' => [
 | 
			
		||||
                '/books' => [
 | 
			
		||||
                    'text' => trans('entities.books'),
 | 
			
		||||
                    'icon' => 'book'
 | 
			
		||||
                ],
 | 
			
		||||
                '/create-book' => [
 | 
			
		||||
                    'text' => trans('entities.books_create'),
 | 
			
		||||
                    'icon' => 'add'
 | 
			
		||||
                ]
 | 
			
		||||
            ]])
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
<div class="container small">
 | 
			
		||||
    <p> </p>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
        <h3>@icon('add') {{ trans('entities.books_create') }}</h3>
 | 
			
		||||
        <div class="body">
 | 
			
		||||
        <div class="content-wrap card">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('entities.books_create') }}</h1>
 | 
			
		||||
            <form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
 | 
			
		||||
                @include('books/form')
 | 
			
		||||
                @include('books.form')
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<p class="margin-top large"><br></p>
 | 
			
		||||
 | 
			
		||||
    @include('components.image-manager', ['imageType' => 'cover'])
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +1,30 @@
 | 
			
		|||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('toolbar')
 | 
			
		||||
    <div class="col-sm-12 faded">
 | 
			
		||||
        @include('books._breadcrumbs', ['book' => $book])
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
 | 
			
		||||
    <div class="container small">
 | 
			
		||||
        <p> </p>
 | 
			
		||||
        <div class="card">
 | 
			
		||||
            <h3>@icon('delete') {{ trans('entities.books_delete') }}</h3>
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p>
 | 
			
		||||
                <p class="text-neg">{{ trans('entities.books_delete_confirmation') }}</p>
 | 
			
		||||
 | 
			
		||||
                <form action="{{$book->getUrl()}}" method="POST">
 | 
			
		||||
                    {!! csrf_field() !!}
 | 
			
		||||
                    <input type="hidden" name="_method" value="DELETE">
 | 
			
		||||
                    <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
 | 
			
		||||
                    <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
        <div class="my-s">
 | 
			
		||||
            @include('partials.breadcrumbs', ['crumbs' => [
 | 
			
		||||
                $book,
 | 
			
		||||
                $book->getUrl('/delete') => [
 | 
			
		||||
                    'text' => trans('entities.books_delete'),
 | 
			
		||||
                    'icon' => 'delete',
 | 
			
		||||
                ]
 | 
			
		||||
            ]])
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card content-wrap auto-height">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('entities.books_delete') }}</h1>
 | 
			
		||||
            <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p>
 | 
			
		||||
            <p class="text-neg"><strong>{{ trans('entities.books_delete_confirmation') }}</strong></p>
 | 
			
		||||
 | 
			
		||||
            <form action="{{$book->getUrl()}}" method="POST" class="text-right">
 | 
			
		||||
                {!! csrf_field() !!}
 | 
			
		||||
                <input type="hidden" name="_method" value="DELETE">
 | 
			
		||||
                <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
 | 
			
		||||
                <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,24 +1,27 @@
 | 
			
		|||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('toolbar')
 | 
			
		||||
    <div class="col-sm-12 faded">
 | 
			
		||||
        @include('books._breadcrumbs', ['book' => $book])
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
 | 
			
		||||
    <div class="container small">
 | 
			
		||||
        <p> </p>
 | 
			
		||||
        <div class="card">
 | 
			
		||||
            <h3>@icon('edit') {{ trans('entities.books_edit') }}</h3>
 | 
			
		||||
            <div class="body">
 | 
			
		||||
                <form action="{{ $book->getUrl() }}" method="POST">
 | 
			
		||||
                    <input type="hidden" name="_method" value="PUT">
 | 
			
		||||
                    @include('books/form', ['model' => $book])
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        <div class="my-s">
 | 
			
		||||
            @include('partials.breadcrumbs', ['crumbs' => [
 | 
			
		||||
                $book,
 | 
			
		||||
                $book->getUrl('/edit') => [
 | 
			
		||||
                    'text' => trans('entities.books_edit'),
 | 
			
		||||
                    'icon' => 'edit',
 | 
			
		||||
                ]
 | 
			
		||||
            ]])
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="content-wrap card">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('entities.books_edit') }}</h1>
 | 
			
		||||
            <form action="{{ $book->getUrl() }}" method="POST">
 | 
			
		||||
                <input type="hidden" name="_method" value="PUT">
 | 
			
		||||
                @include('books.form', ['model' => $book])
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@include('components.image-manager', ['imageType' => 'cover'])
 | 
			
		||||
 | 
			
		||||
    @include('components.image-manager', ['imageType' => 'cover'])
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -31,51 +31,51 @@
 | 
			
		|||
    @include('partials.custom-head')
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-md-8 col-md-offset-2">
 | 
			
		||||
            <div class="page-content">
 | 
			
		||||
 | 
			
		||||
                <h1 style="font-size: 4.8em">{{$book->name}}</h1>
 | 
			
		||||
<div class="page-content">
 | 
			
		||||
 | 
			
		||||
                <p>{{ $book->description }}</p>
 | 
			
		||||
    <h1 style="font-size: 4.8em">{{$book->name}}</h1>
 | 
			
		||||
 | 
			
		||||
                @if(count($bookChildren) > 0)
 | 
			
		||||
                <ul class="contents">
 | 
			
		||||
                    @foreach($bookChildren as $bookChild)
 | 
			
		||||
                        <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
 | 
			
		||||
                        @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
 | 
			
		||||
                            <ul>
 | 
			
		||||
                                @foreach($bookChild->pages as $page)
 | 
			
		||||
                                    <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
 | 
			
		||||
                                @endforeach
 | 
			
		||||
                            </ul>
 | 
			
		||||
                        @endif
 | 
			
		||||
                    @endforeach
 | 
			
		||||
                </ul>
 | 
			
		||||
    <p>{{ $book->description }}</p>
 | 
			
		||||
 | 
			
		||||
    @if(count($bookChildren) > 0)
 | 
			
		||||
        <ul class="contents">
 | 
			
		||||
            @foreach($bookChildren as $bookChild)
 | 
			
		||||
                <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
 | 
			
		||||
                @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        @foreach($bookChild->pages as $page)
 | 
			
		||||
                            <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
 | 
			
		||||
                        @endforeach
 | 
			
		||||
                    </ul>
 | 
			
		||||
                @endif
 | 
			
		||||
            @endforeach
 | 
			
		||||
        </ul>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
                @foreach($bookChildren as $bookChild)
 | 
			
		||||
    @foreach($bookChildren as $bookChild)
 | 
			
		||||
        <div class="page-break"></div>
 | 
			
		||||
        <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
 | 
			
		||||
 | 
			
		||||
        @if($bookChild->isA('chapter'))
 | 
			
		||||
            <p>{{ $bookChild->description }}</p>
 | 
			
		||||
 | 
			
		||||
            @if(count($bookChild->pages) > 0)
 | 
			
		||||
                @foreach($bookChild->pages as $page)
 | 
			
		||||
                    <div class="page-break"></div>
 | 
			
		||||
                    <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
 | 
			
		||||
                    @if($bookChild->isA('chapter'))
 | 
			
		||||
                        <p>{{ $bookChild->description }}</p>
 | 
			
		||||
                        @if(count($bookChild->pages) > 0)
 | 
			
		||||
                            @foreach($bookChild->pages as $page)
 | 
			
		||||
                                <div class="page-break"></div>
 | 
			
		||||
                                <div class="chapter-hint">{{$bookChild->name}}</div>
 | 
			
		||||
                                <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
 | 
			
		||||
                                {!! $page->html !!}
 | 
			
		||||
                            @endforeach
 | 
			
		||||
                        @endif
 | 
			
		||||
                    @else
 | 
			
		||||
                        {!! $bookChild->html !!}
 | 
			
		||||
                    @endif
 | 
			
		||||
                    <div class="chapter-hint">{{$bookChild->name}}</div>
 | 
			
		||||
                    <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
 | 
			
		||||
                    {!! $page->html !!}
 | 
			
		||||
                @endforeach
 | 
			
		||||
            @endif
 | 
			
		||||
 | 
			
		||||
        @else
 | 
			
		||||
            {!! $bookChild->html !!}
 | 
			
		||||
        @endif
 | 
			
		||||
 | 
			
		||||
    @endforeach
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,12 @@
 | 
			
		|||
{{ csrf_field() }}
 | 
			
		||||
<div class="form-group title-input">
 | 
			
		||||
    <label for="name">{{ trans('common.name') }}</label>
 | 
			
		||||
    @include('form/text', ['name' => 'name'])
 | 
			
		||||
    @include('form.text', ['name' => 'name'])
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="form-group description-input">
 | 
			
		||||
    <label for="description">{{ trans('common.description') }}</label>
 | 
			
		||||
    @include('form/textarea', ['name' => 'description'])
 | 
			
		||||
    @include('form.textarea', ['name' => 'description'])
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="form-group" collapsible id="logo-control">
 | 
			
		||||
| 
						 | 
				
			
			@ -41,5 +41,5 @@
 | 
			
		|||
 | 
			
		||||
<div class="form-group text-right">
 | 
			
		||||
    <a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
 | 
			
		||||
    <button type="submit" class="button pos">{{ trans('entities.books_save') }}</button>
 | 
			
		||||
    <button type="submit" class="button primary">{{ trans('entities.books_save') }}</button>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +1,19 @@
 | 
			
		|||
<div class="book-grid-item grid-card"  data-entity-type="book" data-entity-id="{{$book->id}}">
 | 
			
		||||
    <div class="featured-image-container">
 | 
			
		||||
        <a href="{{$book->getUrl()}}" title="{{$book->name}}">
 | 
			
		||||
            <img src="{{$book->getBookCover()}}" alt="{{$book->name}}">
 | 
			
		||||
        </a>
 | 
			
		||||
<a href="{{$book->getUrl()}}" class="grid-card"  data-entity-type="book" data-entity-id="{{$book->id}}">
 | 
			
		||||
    <div class="bg-book featured-image-container-wrap">
 | 
			
		||||
        <div class="featured-image-container" @if($book->cover) style="background-image: url('{{ $book->getBookCover() }}')"@endif>
 | 
			
		||||
        </div>
 | 
			
		||||
        @icon('book')
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="grid-card-content">
 | 
			
		||||
        <h2><a class="break-text" href="{{$book->getUrl()}}" title="{{$book->name}}">{{$book->getShortName(35)}}</a></h2>
 | 
			
		||||
        <h2>{{$book->getShortName(35)}}</h2>
 | 
			
		||||
        @if(isset($book->searchSnippet))
 | 
			
		||||
            <p >{!! $book->searchSnippet !!}</p>
 | 
			
		||||
            <p class="text-muted">{!! $book->searchSnippet !!}</p>
 | 
			
		||||
        @else
 | 
			
		||||
            <p >{{ $book->getExcerpt(130) }}</p>
 | 
			
		||||
            <p class="text-muted">{{ $book->getExcerpt(130) }}</p>
 | 
			
		||||
        @endif
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="grid-card-footer text-muted text-small">
 | 
			
		||||
        <span>@include('partials.entity-meta', ['entity' => $book])</span>
 | 
			
		||||
    <div class="grid-card-footer text-muted ">
 | 
			
		||||
        <p>@icon('star')<span title="{{$book->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $book->created_at->diffForHumans()]) }}</span></p>
 | 
			
		||||
        <p>@icon('edit')<span title="{{ $book->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $book->updated_at->diffForHumans()]) }}</span></p>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</a>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,47 +1,52 @@
 | 
			
		|||
@extends('sidebar-layout')
 | 
			
		||||
@extends('tri-layout')
 | 
			
		||||
 | 
			
		||||
@section('toolbar')
 | 
			
		||||
    <div class="col-xs-6">
 | 
			
		||||
        <div class="action-buttons text-left">
 | 
			
		||||
            @include('books/view-toggle', ['booksViewType' => $booksViewType])
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-xs-6 faded">
 | 
			
		||||
        <div class="action-buttons">
 | 
			
		||||
            @if($currentUser->can('book-create-all'))
 | 
			
		||||
                <a href="{{ baseUrl("/create-book") }}" class="text-pos text-button">@icon('add'){{ trans('entities.books_create') }}</a>
 | 
			
		||||
            @endif
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@section('container-classes', 'mt-xl')
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
    @include('books.list', ['books' => $books, 'view' => $view])
 | 
			
		||||
@stop
 | 
			
		||||
 | 
			
		||||
@section('sidebar')
 | 
			
		||||
@section('left')
 | 
			
		||||
    @if($recents)
 | 
			
		||||
        <div id="recents" class="card">
 | 
			
		||||
            <h3>@icon('view') {{ trans('entities.recently_viewed') }}</h3>
 | 
			
		||||
            @include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
 | 
			
		||||
        <div id="recents" class="mb-xl">
 | 
			
		||||
            <h5>{{ trans('entities.recently_viewed') }}</h5>
 | 
			
		||||
            @include('partials.entity-list', ['entities' => $recents, 'style' => 'compact'])
 | 
			
		||||
        </div>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    <div id="popular" class="card">
 | 
			
		||||
        <h3>@icon('popular') {{ trans('entities.books_popular') }}</h3>
 | 
			
		||||
    <div id="popular" class="mb-xl">
 | 
			
		||||
        <h5>{{ trans('entities.books_popular') }}</h5>
 | 
			
		||||
        @if(count($popular) > 0)
 | 
			
		||||
            @include('partials/entity-list', ['entities' => $popular, 'style' => 'compact'])
 | 
			
		||||
            @include('partials.entity-list', ['entities' => $popular, 'style' => 'compact'])
 | 
			
		||||
        @else
 | 
			
		||||
            <div class="body text-muted">{{ trans('entities.books_popular_empty') }}</div>
 | 
			
		||||
        @endif
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="new" class="card">
 | 
			
		||||
        <h3>@icon('star-circle') {{ trans('entities.books_new') }}</h3>
 | 
			
		||||
    <div id="new" class="mb-xl">
 | 
			
		||||
        <h5>{{ trans('entities.books_new') }}</h5>
 | 
			
		||||
        @if(count($popular) > 0)
 | 
			
		||||
            @include('partials/entity-list', ['entities' => $new, 'style' => 'compact'])
 | 
			
		||||
            @include('partials.entity-list', ['entities' => $new, 'style' => 'compact'])
 | 
			
		||||
        @else
 | 
			
		||||
            <div class="body text-muted">{{ trans('entities.books_new_empty') }}</div>
 | 
			
		||||
        @endif
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
    @include('books/list', ['books' => $books, 'bookViewType' => $booksViewType])
 | 
			
		||||
@section('right')
 | 
			
		||||
 | 
			
		||||
    <div class="actions mb-xl">
 | 
			
		||||
        <h5>{{ trans('common.actions') }}</h5>
 | 
			
		||||
        <div class="icon-list text-primary">
 | 
			
		||||
            @if($currentUser->can('book-create-all'))
 | 
			
		||||
                <a href="{{ baseUrl("/create-book") }}" class="icon-list-item">
 | 
			
		||||
                    <span>@icon('add')</span>
 | 
			
		||||
                    <span>{{ trans('entities.books_create') }}</span>
 | 
			
		||||
                </a>
 | 
			
		||||
            @endif
 | 
			
		||||
 | 
			
		||||
            @include('partials.view-toggle', ['view' => $view, 'type' => 'book'])
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
<div class="book entity-list-item"  data-entity-type="book" data-entity-id="{{$book->id}}">
 | 
			
		||||
    <h4 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}">@icon('book')<span class="entity-list-item-name break-text">{{$book->name}}</span></a></h4>
 | 
			
		||||
    <div class="entity-item-snippet">
 | 
			
		||||
        @if(isset($book->searchSnippet))
 | 
			
		||||
            <p class="text-muted break-text">{!! $book->searchSnippet !!}</p>
 | 
			
		||||
        @else
 | 
			
		||||
            <p class="text-muted break-text">{{ $book->getExcerpt() }}</p>
 | 
			
		||||
        @endif
 | 
			
		||||
<a href="{{ $book->getUrl() }}" class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
 | 
			
		||||
    <div class="entity-list-item-image bg-book" style="background-image: url('{{ $book->getBookCover() }}')">
 | 
			
		||||
        @icon('book')
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
    <div class="content">
 | 
			
		||||
        <h4 class="entity-list-item-name break-text">{{ $book->name }}</h4>
 | 
			
		||||
        <div class="entity-item-snippet">
 | 
			
		||||
            <p class="text-muted break-text mb-s">{{ $book->getExcerpt() }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</a>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +1,30 @@
 | 
			
		|||
 | 
			
		||||
<div class="container{{ $booksViewType === 'list' ? ' small' : '' }}">
 | 
			
		||||
    <h1>{{ trans('entities.books') }}</h1>
 | 
			
		||||
<div class="content-wrap mt-m card">
 | 
			
		||||
    <div class="grid half v-center">
 | 
			
		||||
        <h1 class="list-heading">{{ trans('entities.books') }}</h1>
 | 
			
		||||
        <div class="text-right">
 | 
			
		||||
 | 
			
		||||
            @include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'books'])
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    @if(count($books) > 0)
 | 
			
		||||
        @if($booksViewType === 'list')
 | 
			
		||||
            @foreach($books as $book)
 | 
			
		||||
                @include('books/list-item', ['book' => $book])
 | 
			
		||||
                <hr>
 | 
			
		||||
            @endforeach
 | 
			
		||||
            {!! $books->render() !!}
 | 
			
		||||
        @if($view === 'list')
 | 
			
		||||
            <div class="entity-list">
 | 
			
		||||
                @foreach($books as $book)
 | 
			
		||||
                    @include('books.list-item', ['book' => $book])
 | 
			
		||||
                @endforeach
 | 
			
		||||
            </div>
 | 
			
		||||
        @else
 | 
			
		||||
             <div class="grid third">
 | 
			
		||||
                @foreach($books as $key => $book)
 | 
			
		||||
                        @include('books/grid-item', ['book' => $book])
 | 
			
		||||
                    @include('books.grid-item', ['book' => $book])
 | 
			
		||||
                @endforeach
 | 
			
		||||
             </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                {!! $books->render() !!}
 | 
			
		||||
            </div>
 | 
			
		||||
        @endif
 | 
			
		||||
        <div>
 | 
			
		||||
            {!! $books->render() !!}
 | 
			
		||||
        </div>
 | 
			
		||||
    @else
 | 
			
		||||
        <p class="text-muted">{{ trans('entities.books_empty') }}</p>
 | 
			
		||||
        @if(userCan('books-create-all'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
@extends('simple-layout')
 | 
			
		||||
 | 
			
		||||
@section('body')
 | 
			
		||||
 | 
			
		||||
    <div class="container">
 | 
			
		||||
 | 
			
		||||
        <div class="my-s">
 | 
			
		||||
            @include('partials.breadcrumbs', ['crumbs' => [
 | 
			
		||||
                $book,
 | 
			
		||||
                $book->getUrl('/permissions') => [
 | 
			
		||||
                    'text' => trans('entities.books_permissions'),
 | 
			
		||||
                    'icon' => 'lock',
 | 
			
		||||
                ]
 | 
			
		||||
            ]])
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card content-wrap">
 | 
			
		||||
            <h1 class="list-heading">{{ trans('entities.books_permissions') }}</h1>
 | 
			
		||||
            @include('form.entity-permissions', ['model' => $book])
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||