Merge pull request #1153 from BookStackApp/2019-design
WIP: 2019 design
@ -103,7 +103,7 @@ class ActivityService
|
|||||||
* @param int $page
|
* @param int $page
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function entityActivity($entity, $count = 20, $page = 0)
|
public function entityActivity($entity, $count = 20, $page = 1)
|
||||||
{
|
{
|
||||||
if ($entity->isA('book')) {
|
if ($entity->isA('book')) {
|
||||||
$query = $this->activity->where('book_id', '=', $entity->id);
|
$query = $this->activity->where('book_id', '=', $entity->id);
|
||||||
@ -114,7 +114,7 @@ class ActivityService
|
|||||||
|
|
||||||
$activity = $this->permissionService
|
$activity = $this->permissionService
|
||||||
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
->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);
|
return $this->filterSimilar($activity);
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,26 @@
|
|||||||
|
|
||||||
use BookStack\Auth\Permissions\PermissionService;
|
use BookStack\Auth\Permissions\PermissionService;
|
||||||
use BookStack\Entities\Entity;
|
use BookStack\Entities\Entity;
|
||||||
|
use BookStack\Entities\EntityProvider;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class ViewService
|
class ViewService
|
||||||
{
|
{
|
||||||
protected $view;
|
protected $view;
|
||||||
protected $permissionService;
|
protected $permissionService;
|
||||||
|
protected $entityProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewService constructor.
|
* ViewService constructor.
|
||||||
* @param \BookStack\Actions\View $view
|
* @param \BookStack\Actions\View $view
|
||||||
* @param \BookStack\Auth\Permissions\PermissionService $permissionService
|
* @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->view = $view;
|
||||||
$this->permissionService = $permissionService;
|
$this->permissionService = $permissionService;
|
||||||
|
$this->entityProvider = $entityProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,23 +55,21 @@ class ViewService
|
|||||||
* Get the entities with the most views.
|
* Get the entities with the most views.
|
||||||
* @param int $count
|
* @param int $count
|
||||||
* @param int $page
|
* @param int $page
|
||||||
* @param Entity|false|array $filterModel
|
* @param string|array $filterModels
|
||||||
* @param string $action - used for permission checking
|
* @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;
|
$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'))
|
->select('*', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
|
||||||
->groupBy('viewable_id', 'viewable_type')
|
->groupBy('viewable_id', 'viewable_type')
|
||||||
->orderBy('view_count', 'desc');
|
->orderBy('view_count', 'desc');
|
||||||
|
|
||||||
if ($filterModel && is_array($filterModel)) {
|
if ($filterModels) {
|
||||||
$query->whereIn('viewable_type', $filterModel);
|
$query->whereIn('viewable_type', $this->entityProvider->getMorphClasses($filterModels));
|
||||||
} else if ($filterModel) {
|
|
||||||
$query->where('viewable_type', '=', $filterModel->getMorphClass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
|
return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
|
||||||
|
@ -704,7 +704,7 @@ class PermissionService
|
|||||||
* @param string $entityIdColumn
|
* @param string $entityIdColumn
|
||||||
* @param string $entityTypeColumn
|
* @param string $entityTypeColumn
|
||||||
* @param string $action
|
* @param string $action
|
||||||
* @return mixed
|
* @return QueryBuilder
|
||||||
*/
|
*/
|
||||||
public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn, $action = 'view')
|
public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn, $action = 'view')
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php namespace BookStack\Auth;
|
<?php namespace BookStack\Auth;
|
||||||
|
|
||||||
use BookStack\Auth\Permissions\JointPermission;
|
use BookStack\Auth\Permissions\JointPermission;
|
||||||
|
use BookStack\Auth\Permissions\RolePermission;
|
||||||
use BookStack\Model;
|
use BookStack\Model;
|
||||||
|
|
||||||
class Role extends Model
|
class Role extends Model
|
||||||
@ -13,7 +14,7 @@ class Role extends Model
|
|||||||
*/
|
*/
|
||||||
public function users()
|
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()
|
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.
|
* 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);
|
$this->permissions()->attach($permission->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach a single permission from this role.
|
* 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);
|
$this->permissions()->detach($permission->id);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use BookStack\Exceptions\NotFoundException;
|
|||||||
use BookStack\Exceptions\UserUpdateException;
|
use BookStack\Exceptions\UserUpdateException;
|
||||||
use BookStack\Uploads\Image;
|
use BookStack\Uploads\Image;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Images;
|
use Images;
|
||||||
|
|
||||||
class UserRepo
|
class UserRepo
|
||||||
@ -48,7 +49,7 @@ class UserRepo
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the users with their permissions.
|
* Get all the users with their permissions.
|
||||||
* @return \Illuminate\Database\Eloquent\Builder|static
|
* @return Builder|static
|
||||||
*/
|
*/
|
||||||
public function getAllUsers()
|
public function getAllUsers()
|
||||||
{
|
{
|
||||||
@ -59,7 +60,7 @@ class UserRepo
|
|||||||
* Get all the users with their permissions in a paginated format.
|
* Get all the users with their permissions in a paginated format.
|
||||||
* @param int $count
|
* @param int $count
|
||||||
* @param $sortData
|
* @param $sortData
|
||||||
* @return \Illuminate\Database\Eloquent\Builder|static
|
* @return Builder|static
|
||||||
*/
|
*/
|
||||||
public function getAllUsersPaginatedAndSorted($count, $sortData)
|
public function getAllUsersPaginatedAndSorted($count, $sortData)
|
||||||
{
|
{
|
||||||
@ -223,16 +224,15 @@ class UserRepo
|
|||||||
*/
|
*/
|
||||||
public function getRecentlyCreated(User $user, $count = 20)
|
public function getRecentlyCreated(User $user, $count = 20)
|
||||||
{
|
{
|
||||||
|
$createdByUserQuery = function(Builder $query) use ($user) {
|
||||||
|
$query->where('created_by', '=', $user->id);
|
||||||
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) {
|
'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, $createdByUserQuery),
|
||||||
$query->where('created_by', '=', $user->id);
|
'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, $createdByUserQuery),
|
||||||
}),
|
'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, $createdByUserQuery),
|
||||||
'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) {
|
'shelves' => $this->entityRepo->getRecentlyCreated('bookshelf', $count, 0, $createdByUserQuery)
|
||||||
$query->where('created_by', '=', $user->id);
|
|
||||||
}),
|
|
||||||
'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) {
|
|
||||||
$query->where('created_by', '=', $user->id);
|
|
||||||
})
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +247,7 @@ class UserRepo
|
|||||||
'pages' => $this->entityRepo->getUserTotalCreated('page', $user),
|
'pages' => $this->entityRepo->getUserTotalCreated('page', $user),
|
||||||
'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user),
|
'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user),
|
||||||
'books' => $this->entityRepo->getUserTotalCreated('book', $user),
|
'books' => $this->entityRepo->getUserTotalCreated('book', $user),
|
||||||
|
'shelves' => $this->entityRepo->getUserTotalCreated('bookshelf', $user),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +257,7 @@ class UserRepo
|
|||||||
*/
|
*/
|
||||||
public function getAllRoles()
|
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)
|
public function getBookCover($width = 440, $height = 250)
|
||||||
{
|
{
|
||||||
$default = baseUrl('/book_default_cover.png');
|
$default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
||||||
if (!$this->image_id) {
|
if (!$this->image_id) {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
@ -69,6 +69,15 @@ class Book extends Entity
|
|||||||
return $this->hasMany(Page::class);
|
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.
|
* Get all chapters within this book.
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
@ -92,7 +101,7 @@ class Book extends Entity
|
|||||||
* @param int $length
|
* @param int $length
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getExcerpt($length = 100)
|
public function getExcerpt(int $length = 100)
|
||||||
{
|
{
|
||||||
$description = $this->description;
|
$description = $this->description;
|
||||||
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $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)
|
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) {
|
if (!$this->image_id) {
|
||||||
return $default;
|
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
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
*/
|
*/
|
||||||
public function cover()
|
public function cover()
|
||||||
@ -77,7 +78,7 @@ class Bookshelf extends Entity
|
|||||||
* @param int $length
|
* @param int $length
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getExcerpt($length = 100)
|
public function getExcerpt(int $length = 100)
|
||||||
{
|
{
|
||||||
$description = $this->description;
|
$description = $this->description;
|
||||||
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $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";
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
34
app/Entities/BreadcrumbsViewComposer.php
Normal file
@ -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
|
* @param int $length
|
||||||
* @return string
|
* @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;
|
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";
|
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');
|
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.
|
* Get the Tag models that have been user assigned to this entity.
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
|
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
|
||||||
@ -218,6 +223,20 @@ class Entity extends Ownable
|
|||||||
return $this->{$this->textField};
|
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 a generalised, common raw query that can be 'unioned' across entities.
|
||||||
* @return string
|
* @return string
|
||||||
|
62
app/Entities/EntityContextManager.php
Normal file
@ -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);
|
$type = strtolower($type);
|
||||||
return $this->all()[$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);
|
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.
|
* Return a generalised, common raw query that can be 'unioned' across entities.
|
||||||
* @param bool $withContent
|
* @param bool $withContent
|
||||||
|
@ -62,4 +62,5 @@ class PageRevision extends Model
|
|||||||
{
|
{
|
||||||
return $type === 'revision';
|
return $type === 'revision';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use BookStack\Exceptions\NotFoundException;
|
|||||||
use BookStack\Exceptions\NotifyException;
|
use BookStack\Exceptions\NotifyException;
|
||||||
use BookStack\Uploads\AttachmentService;
|
use BookStack\Uploads\AttachmentService;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
@ -179,11 +180,38 @@ class EntityRepo
|
|||||||
* Get all entities in a paginated format
|
* Get all entities in a paginated format
|
||||||
* @param $type
|
* @param $type
|
||||||
* @param int $count
|
* @param int $count
|
||||||
|
* @param string $sort
|
||||||
|
* @param string $order
|
||||||
|
* @param null|callable $queryAddition
|
||||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
* @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.
|
* Get the most popular entities base on all views.
|
||||||
* @param string|bool $type
|
* @param string $type
|
||||||
* @param int $count
|
* @param int $count
|
||||||
* @param int $page
|
* @param int $page
|
||||||
* @return mixed
|
* @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, $type);
|
||||||
return $this->viewService->getPopular($count, $page, $filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,6 +340,18 @@ class EntityRepo
|
|||||||
return $this->permissionService->enforceEntityRestrictions('book', $bookshelf->books())->get();
|
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.
|
* Get all child objects of a book.
|
||||||
* Returns a sorted collection of Pages and Chapters.
|
* 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()
|
public function getRegisterConfirmation()
|
||||||
{
|
{
|
||||||
return view('auth/register-confirm');
|
return view('auth.register-confirm');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,7 +204,7 @@ class RegisterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showAwaitingConfirmation()
|
public function showAwaitingConfirmation()
|
||||||
{
|
{
|
||||||
return view('auth/user-unconfirmed');
|
return view('auth.user-unconfirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use Activity;
|
use Activity;
|
||||||
use BookStack\Auth\UserRepo;
|
use BookStack\Auth\UserRepo;
|
||||||
use BookStack\Entities\Book;
|
use BookStack\Entities\Book;
|
||||||
|
use BookStack\Entities\EntityContextManager;
|
||||||
use BookStack\Entities\Repos\EntityRepo;
|
use BookStack\Entities\Repos\EntityRepo;
|
||||||
use BookStack\Entities\ExportService;
|
use BookStack\Entities\ExportService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -15,18 +16,25 @@ class BookController extends Controller
|
|||||||
protected $entityRepo;
|
protected $entityRepo;
|
||||||
protected $userRepo;
|
protected $userRepo;
|
||||||
protected $exportService;
|
protected $exportService;
|
||||||
|
protected $entityContextManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BookController constructor.
|
* BookController constructor.
|
||||||
* @param EntityRepo $entityRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param \BookStack\Auth\UserRepo $userRepo
|
* @param UserRepo $userRepo
|
||||||
* @param \BookStack\Entities\ExportService $exportService
|
* @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->entityRepo = $entityRepo;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
$this->exportService = $exportService;
|
$this->exportService = $exportService;
|
||||||
|
$this->entityContextManager = $entityContextManager;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,18 +44,32 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
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;
|
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
|
||||||
$popular = $this->entityRepo->getPopular('book', 4, 0);
|
$popular = $this->entityRepo->getPopular('book', 4, 0);
|
||||||
$new = $this->entityRepo->getRecentlyCreated('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'));
|
$this->setPageTitle(trans('entities.books'));
|
||||||
return view('books/index', [
|
return view('books.index', [
|
||||||
'books' => $books,
|
'books' => $books,
|
||||||
'recents' => $recents,
|
'recents' => $recents,
|
||||||
'popular' => $popular,
|
'popular' => $popular,
|
||||||
'new' => $new,
|
'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->checkPermission('book-create-all');
|
||||||
$this->setPageTitle(trans('entities.books_create'));
|
$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.
|
* Display the specified book.
|
||||||
* @param $slug
|
* @param $slug
|
||||||
|
* @param Request $request
|
||||||
* @return Response
|
* @return Response
|
||||||
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function show($slug)
|
public function show($slug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->entityRepo->getBySlug('book', $slug);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-view', $book);
|
$this->checkOwnablePermission('book-view', $book);
|
||||||
|
|
||||||
$bookChildren = $this->entityRepo->getBookChildren($book);
|
$bookChildren = $this->entityRepo->getBookChildren($book);
|
||||||
|
|
||||||
Views::add($book);
|
Views::add($book);
|
||||||
|
if ($request->has('shelf')) {
|
||||||
|
$this->entityContextManager->setShelfContext(intval($request->get('shelf')));
|
||||||
|
}
|
||||||
|
|
||||||
$this->setPageTitle($book->getShortName());
|
$this->setPageTitle($book->getShortName());
|
||||||
return view('books/show', [
|
return view('books.show', [
|
||||||
'book' => $book,
|
'book' => $book,
|
||||||
'current' => $book,
|
'current' => $book,
|
||||||
'bookChildren' => $bookChildren,
|
'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);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
$this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()]));
|
$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);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-delete', $book);
|
$this->checkOwnablePermission('book-delete', $book);
|
||||||
$this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
|
$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.
|
* Shows the view which allows pages to be re-ordered and sorted.
|
||||||
* @param string $bookSlug
|
* @param string $bookSlug
|
||||||
* @return \Illuminate\View\View
|
* @return \Illuminate\View\View
|
||||||
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function sort($bookSlug)
|
public function sort($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
|
|
||||||
$bookChildren = $this->entityRepo->getBookChildren($book, true);
|
$bookChildren = $this->entityRepo->getBookChildren($book, true);
|
||||||
$books = $this->entityRepo->getAll('book', false, 'update');
|
|
||||||
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
|
$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);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$bookChildren = $this->entityRepo->getBookChildren($book);
|
$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
|
* @param $bookSlug
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function showRestrict($bookSlug)
|
public function showPermissions($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('books/restrictions', [
|
return view('books.permissions', [
|
||||||
'book' => $book,
|
'book' => $book,
|
||||||
'roles' => $roles
|
'roles' => $roles
|
||||||
]);
|
]);
|
||||||
@ -277,11 +309,12 @@ class BookController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Set the restrictions for this book.
|
* Set the restrictions for this book.
|
||||||
* @param $bookSlug
|
* @param $bookSlug
|
||||||
* @param $bookSlug
|
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
* @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);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use Activity;
|
use Activity;
|
||||||
use BookStack\Auth\UserRepo;
|
use BookStack\Auth\UserRepo;
|
||||||
use BookStack\Entities\Bookshelf;
|
use BookStack\Entities\Bookshelf;
|
||||||
|
use BookStack\Entities\EntityContextManager;
|
||||||
use BookStack\Entities\Repos\EntityRepo;
|
use BookStack\Entities\Repos\EntityRepo;
|
||||||
use BookStack\Entities\ExportService;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Views;
|
use Views;
|
||||||
@ -14,19 +14,19 @@ class BookshelfController extends Controller
|
|||||||
|
|
||||||
protected $entityRepo;
|
protected $entityRepo;
|
||||||
protected $userRepo;
|
protected $userRepo;
|
||||||
protected $exportService;
|
protected $entityContextManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BookController constructor.
|
* BookController constructor.
|
||||||
* @param \BookStack\Entities\Repos\EntityRepo $entityRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param UserRepo $userRepo
|
* @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->entityRepo = $entityRepo;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
$this->exportService = $exportService;
|
$this->entityContextManager = $entityContextManager;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,19 +36,35 @@ class BookshelfController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
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;
|
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false;
|
||||||
$popular = $this->entityRepo->getPopular('bookshelf', 4, 0);
|
$popular = $this->entityRepo->getPopular('bookshelf', 4, 0);
|
||||||
$new = $this->entityRepo->getRecentlyCreated('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'));
|
$this->setPageTitle(trans('entities.shelves'));
|
||||||
return view('shelves/index', [
|
return view('shelves.index', [
|
||||||
'shelves' => $shelves,
|
'shelves' => $shelves,
|
||||||
'recents' => $recents,
|
'recents' => $recents,
|
||||||
'popular' => $popular,
|
'popular' => $popular,
|
||||||
'new' => $new,
|
'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');
|
$this->checkPermission('bookshelf-create-all');
|
||||||
$books = $this->entityRepo->getAll('book', false, 'update');
|
$books = $this->entityRepo->getAll('book', false, 'update');
|
||||||
$this->setPageTitle(trans('entities.shelves_create'));
|
$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)
|
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);
|
$this->checkOwnablePermission('book-view', $bookshelf);
|
||||||
|
|
||||||
$books = $this->entityRepo->getBookshelfChildren($bookshelf);
|
$books = $this->entityRepo->getBookshelfChildren($bookshelf);
|
||||||
Views::add($bookshelf);
|
Views::add($bookshelf);
|
||||||
|
$this->entityContextManager->setShelfContext($bookshelf->id);
|
||||||
|
|
||||||
$this->setPageTitle($bookshelf->getShortName());
|
$this->setPageTitle($bookshelf->getShortName());
|
||||||
return view('shelves/show', [
|
return view('shelves.show', [
|
||||||
'shelf' => $bookshelf,
|
'shelf' => $bookshelf,
|
||||||
'books' => $books,
|
'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()]));
|
$this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $bookshelf->getShortName()]));
|
||||||
return view('shelves/edit', [
|
return view('shelves.edit', [
|
||||||
'shelf' => $bookshelf,
|
'shelf' => $bookshelf,
|
||||||
'books' => $books,
|
'books' => $books,
|
||||||
'shelfBooks' => $shelfBooks,
|
'shelfBooks' => $shelfBooks,
|
||||||
@ -170,7 +188,7 @@ class BookshelfController extends Controller
|
|||||||
$this->checkOwnablePermission('bookshelf-delete', $bookshelf);
|
$this->checkOwnablePermission('bookshelf-delete', $bookshelf);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $bookshelf->getShortName()]));
|
$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.
|
* Show the permissions view.
|
||||||
* @param $slug
|
* @param string $slug
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function showRestrict(string $slug)
|
public function showPermissions(string $slug)
|
||||||
{
|
{
|
||||||
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
|
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
|
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
|
||||||
|
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('shelves.restrictions', [
|
return view('shelves.permissions', [
|
||||||
'shelf' => $bookshelf,
|
'shelf' => $bookshelf,
|
||||||
'roles' => $roles
|
'roles' => $roles
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the restrictions for this bookshelf.
|
* Set the permissions for this bookshelf.
|
||||||
* @param $slug
|
* @param string $slug
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @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);
|
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
|
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
|
||||||
|
@ -39,7 +39,7 @@ class ChapterController extends Controller
|
|||||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-create', $book);
|
$this->checkOwnablePermission('chapter-create', $book);
|
||||||
$this->setPageTitle(trans('entities.chapters_create'));
|
$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);
|
Views::add($chapter);
|
||||||
$this->setPageTitle($chapter->getShortName());
|
$this->setPageTitle($chapter->getShortName());
|
||||||
$pages = $this->entityRepo->getChapterChildren($chapter);
|
$pages = $this->entityRepo->getChapterChildren($chapter);
|
||||||
return view('chapters/show', [
|
return view('chapters.show', [
|
||||||
'book' => $chapter->book,
|
'book' => $chapter->book,
|
||||||
'chapter' => $chapter,
|
'chapter' => $chapter,
|
||||||
'current' => $chapter,
|
'current' => $chapter,
|
||||||
@ -98,7 +98,7 @@ class ChapterController extends Controller
|
|||||||
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
|
$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);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||||
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
|
$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->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||||
return view('chapters/move', [
|
return view('chapters.move', [
|
||||||
'chapter' => $chapter,
|
'chapter' => $chapter,
|
||||||
'book' => $chapter->book
|
'book' => $chapter->book
|
||||||
]);
|
]);
|
||||||
@ -214,13 +214,14 @@ class ChapterController extends Controller
|
|||||||
* @param $bookSlug
|
* @param $bookSlug
|
||||||
* @param $chapterSlug
|
* @param $chapterSlug
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @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);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('chapters/restrictions', [
|
return view('chapters.permissions', [
|
||||||
'chapter' => $chapter,
|
'chapter' => $chapter,
|
||||||
'roles' => $roles
|
'roles' => $roles
|
||||||
]);
|
]);
|
||||||
@ -232,8 +233,10 @@ class ChapterController extends Controller
|
|||||||
* @param $chapterSlug
|
* @param $chapterSlug
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
* @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);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
|
@ -54,7 +54,7 @@ class CommentController extends Controller
|
|||||||
$this->checkPermission('comment-create-all');
|
$this->checkPermission('comment-create-all');
|
||||||
$comment = $this->commentRepo->create($page, $request->only(['html', 'text', 'parent_id']));
|
$comment = $this->commentRepo->create($page, $request->only(['html', 'text', 'parent_id']));
|
||||||
Activity::add($page, 'commented_on', $page->book->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);
|
$this->checkOwnablePermission('comment-update', $comment);
|
||||||
|
|
||||||
$comment = $this->commentRepo->update($comment, $request->only(['html', 'text']));
|
$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;
|
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.
|
* Send back a json error message.
|
||||||
* @param string $messageText
|
* @param string $messageText
|
||||||
|
@ -19,7 +19,6 @@ class HomeController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the homepage.
|
* Display the homepage.
|
||||||
* @return Response
|
* @return Response
|
||||||
@ -45,17 +44,36 @@ class HomeController extends Controller
|
|||||||
'draftPages' => $draftPages,
|
'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') {
|
if ($homepageOption === 'bookshelves') {
|
||||||
$shelves = $this->entityRepo->getAllPaginated('bookshelf', 18);
|
$shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $commonData['sort'], $commonData['order']);
|
||||||
$shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
|
$data = array_merge($commonData, ['shelves' => $shelves]);
|
||||||
$data = array_merge($commonData, ['shelves' => $shelves, 'shelvesViewType' => $shelvesViewType]);
|
|
||||||
return view('common.home-shelves', $data);
|
return view('common.home-shelves', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($homepageOption === 'books') {
|
if ($homepageOption === 'books') {
|
||||||
$books = $this->entityRepo->getAllPaginated('book', 18);
|
$books = $this->entityRepo->getAllPaginated('book', 18, $commonData['sort'], $commonData['order']);
|
||||||
$booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
|
$data = array_merge($commonData, ['books' => $books]);
|
||||||
$data = array_merge($commonData, ['books' => $books, 'booksViewType' => $booksViewType]);
|
|
||||||
return view('common.home-book', $data);
|
return view('common.home-book', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +123,7 @@ class HomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function customHeadContent()
|
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;
|
$allowRobots = $sitePublic;
|
||||||
}
|
}
|
||||||
return response()
|
return response()
|
||||||
->view('common/robots', ['allowRobots' => $allowRobots])
|
->view('common.robots', ['allowRobots' => $allowRobots])
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +147,6 @@ class HomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function getNotFound()
|
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
|
// Otherwise show the edit view if they're a guest
|
||||||
$this->setPageTitle(trans('entities.pages_new'));
|
$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'));
|
$this->setPageTitle(trans('entities.pages_edit_draft'));
|
||||||
|
|
||||||
$draftsEnabled = $this->signedIn;
|
$draftsEnabled = $this->signedIn;
|
||||||
return view('pages/edit', [
|
return view('pages.edit', [
|
||||||
'page' => $draft,
|
'page' => $draft,
|
||||||
'book' => $draft->book,
|
'book' => $draft->book,
|
||||||
'isDraft' => true,
|
'isDraft' => true,
|
||||||
@ -184,7 +184,7 @@ class PageController extends Controller
|
|||||||
|
|
||||||
Views::add($page);
|
Views::add($page);
|
||||||
$this->setPageTitle($page->getShortName());
|
$this->setPageTitle($page->getShortName());
|
||||||
return view('pages/show', [
|
return view('pages.show', [
|
||||||
'page' => $page,'book' => $page->book,
|
'page' => $page,'book' => $page->book,
|
||||||
'current' => $page,
|
'current' => $page,
|
||||||
'sidebarTree' => $sidebarTree,
|
'sidebarTree' => $sidebarTree,
|
||||||
@ -239,7 +239,7 @@ class PageController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$draftsEnabled = $this->signedIn;
|
$draftsEnabled = $this->signedIn;
|
||||||
return view('pages/edit', [
|
return view('pages.edit', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
'current' => $page,
|
'current' => $page,
|
||||||
@ -317,7 +317,7 @@ class PageController extends Controller
|
|||||||
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('page-delete', $page);
|
$this->checkOwnablePermission('page-delete', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
|
$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);
|
$page = $this->pageRepo->getById('page', $pageId, true);
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
|
$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 $bookSlug
|
||||||
* @param string $pageSlug
|
* @param string $pageSlug
|
||||||
* @return \Illuminate\View\View
|
* @return \Illuminate\View\View
|
||||||
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
public function showRevisions($bookSlug, $pageSlug)
|
public function showRevisions($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
||||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
$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());
|
$page->fill($revision->toArray());
|
||||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
|
||||||
|
|
||||||
return view('pages/revision', [
|
return view('pages.revision', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
|
'diff' => null,
|
||||||
'revision' => $revision
|
'revision' => $revision
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -432,7 +434,7 @@ class PageController extends Controller
|
|||||||
$page->fill($revision->toArray());
|
$page->fill($revision->toArray());
|
||||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
||||||
|
|
||||||
return view('pages/revision', [
|
return view('pages.revision', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
'diff' => $diff,
|
'diff' => $diff,
|
||||||
@ -482,12 +484,12 @@ class PageController extends Controller
|
|||||||
// Check if its the latest revision, cannot delete latest revision.
|
// Check if its the latest revision, cannot delete latest revision.
|
||||||
if (intval($currentRevision->id) === intval($revId)) {
|
if (intval($currentRevision->id) === intval($revId)) {
|
||||||
session()->flash('error', trans('entities.revision_cannot_delete_latest'));
|
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();
|
$revision->delete();
|
||||||
session()->flash('success', trans('entities.revision_delete_success'));
|
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');
|
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
|
* Show a listing of recently created pages
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function showRecentlyUpdated()
|
public function showRecentlyUpdated()
|
||||||
{
|
{
|
||||||
|
// TODO - Still exist?
|
||||||
$pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
|
$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'),
|
'title' => trans('entities.recently_updated_pages'),
|
||||||
'pages' => $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.
|
* Show the view to choose a new parent to move a page into.
|
||||||
* @param string $bookSlug
|
* @param string $bookSlug
|
||||||
@ -587,7 +560,7 @@ class PageController extends Controller
|
|||||||
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->checkOwnablePermission('page-delete', $page);
|
$this->checkOwnablePermission('page-delete', $page);
|
||||||
return view('pages/move', [
|
return view('pages.move', [
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
'page' => $page
|
'page' => $page
|
||||||
]);
|
]);
|
||||||
@ -645,7 +618,7 @@ class PageController extends Controller
|
|||||||
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('page-view', $page);
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
session()->flashInput(['name' => $page->name]);
|
session()->flashInput(['name' => $page->name]);
|
||||||
return view('pages/copy', [
|
return view('pages.copy', [
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
'page' => $page
|
'page' => $page
|
||||||
]);
|
]);
|
||||||
@ -690,6 +663,24 @@ class PageController extends Controller
|
|||||||
return redirect($pageCopy->getUrl());
|
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.
|
* Set the permissions for this page.
|
||||||
* @param string $bookSlug
|
* @param string $bookSlug
|
||||||
@ -697,8 +688,9 @@ class PageController extends Controller
|
|||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function restrict($bookSlug, $pageSlug, Request $request)
|
public function permissions($bookSlug, $pageSlug, Request $request)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||||
|
@ -26,7 +26,7 @@ class PermissionController extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkPermission('user-roles-manage');
|
$this->checkPermission('user-roles-manage');
|
||||||
$roles = $this->permissionsRepo->getAllRoles();
|
$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()
|
public function createRole()
|
||||||
{
|
{
|
||||||
$this->checkPermission('user-roles-manage');
|
$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) {
|
if ($role->hidden) {
|
||||||
throw new PermissionsException(trans('errors.role_cannot_be_edited'));
|
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);
|
$roles = $this->permissionsRepo->getAllRolesExcept($role);
|
||||||
$blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]);
|
$blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]);
|
||||||
$roles->prepend($blankRole);
|
$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;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
use BookStack\Actions\ViewService;
|
use BookStack\Actions\ViewService;
|
||||||
|
use BookStack\Entities\EntityContextManager;
|
||||||
use BookStack\Entities\Repos\EntityRepo;
|
use BookStack\Entities\Repos\EntityRepo;
|
||||||
use BookStack\Entities\SearchService;
|
use BookStack\Entities\SearchService;
|
||||||
|
use BookStack\Exceptions\NotFoundException;
|
||||||
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
protected $entityRepo;
|
protected $entityRepo;
|
||||||
protected $viewService;
|
protected $viewService;
|
||||||
protected $searchService;
|
protected $searchService;
|
||||||
|
protected $entityContextManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SearchController constructor.
|
* SearchController constructor.
|
||||||
* @param \BookStack\Entities\Repos\EntityRepo $entityRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param ViewService $viewService
|
* @param ViewService $viewService
|
||||||
* @param SearchService $searchService
|
* @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->entityRepo = $entityRepo;
|
||||||
$this->viewService = $viewService;
|
$this->viewService = $viewService;
|
||||||
$this->searchService = $searchService;
|
$this->searchService = $searchService;
|
||||||
|
$this->entityContextManager = $entityContextManager;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches all entities.
|
* Searches all entities.
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\View\View
|
* @return View
|
||||||
* @internal param string $searchTerm
|
* @internal param string $searchTerm
|
||||||
*/
|
*/
|
||||||
public function search(Request $request)
|
public function search(Request $request)
|
||||||
@ -41,7 +52,7 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
$results = $this->searchService->searchEntities($searchTerm, 'all', $page, 20);
|
$results = $this->searchService->searchEntities($searchTerm, 'all', $page, 20);
|
||||||
|
|
||||||
return view('search/all', [
|
return view('search.all', [
|
||||||
'entities' => $results['results'],
|
'entities' => $results['results'],
|
||||||
'totalResults' => $results['total'],
|
'totalResults' => $results['total'],
|
||||||
'searchTerm' => $searchTerm,
|
'searchTerm' => $searchTerm,
|
||||||
@ -55,28 +66,28 @@ class SearchController extends Controller
|
|||||||
* Searches all entities within a book.
|
* Searches all entities within a book.
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param integer $bookId
|
* @param integer $bookId
|
||||||
* @return \Illuminate\View\View
|
* @return View
|
||||||
* @internal param string $searchTerm
|
* @internal param string $searchTerm
|
||||||
*/
|
*/
|
||||||
public function searchBook(Request $request, $bookId)
|
public function searchBook(Request $request, $bookId)
|
||||||
{
|
{
|
||||||
$term = $request->get('term', '');
|
$term = $request->get('term', '');
|
||||||
$results = $this->searchService->searchBook($bookId, $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.
|
* Searches all entities within a chapter.
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param integer $chapterId
|
* @param integer $chapterId
|
||||||
* @return \Illuminate\View\View
|
* @return View
|
||||||
* @internal param string $searchTerm
|
* @internal param string $searchTerm
|
||||||
*/
|
*/
|
||||||
public function searchChapter(Request $request, $chapterId)
|
public function searchChapter(Request $request, $chapterId)
|
||||||
{
|
{
|
||||||
$term = $request->get('term', '');
|
$term = $request->get('term', '');
|
||||||
$results = $this->searchService->searchChapter($chapterId, $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)
|
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);
|
$searchTerm = $request->get('term', false);
|
||||||
$permission = $request->get('permission', 'view');
|
$permission = $request->get('permission', 'view');
|
||||||
|
|
||||||
// Search for entities otherwise show most popular
|
// Search for entities otherwise show most popular
|
||||||
if ($searchTerm !== false) {
|
if ($searchTerm !== false) {
|
||||||
$searchTerm .= ' {type:'. implode('|', $entityTypes->toArray()) .'}';
|
$searchTerm .= ' {type:'. implode('|', $entityTypes) .'}';
|
||||||
$entities = $this->searchService->searchEntities($searchTerm, 'all', 1, 20, $permission)['results'];
|
$entities = $this->searchService->searchEntities($searchTerm, 'all', 1, 20, $permission)['results'];
|
||||||
} else {
|
} else {
|
||||||
$entityNames = $entityTypes->map(function ($type) {
|
$entities = $this->viewService->getPopular(20, 0, $entityTypes, $permission);
|
||||||
return 'BookStack\\' . ucfirst($type); // TODO - Extract this elsewhere, too specific and stringy
|
|
||||||
})->toArray();
|
|
||||||
$entities = $this->viewService->getPopular(20, 0, $entityNames, $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;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
|
use BookStack\Auth\User;
|
||||||
use BookStack\Uploads\ImageService;
|
use BookStack\Uploads\ImageService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -19,7 +20,10 @@ class SettingController extends Controller
|
|||||||
// Get application version
|
// Get application version
|
||||||
$version = trim(file_get_contents(base_path('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
|
// Get application version
|
||||||
$version = trim(file_get_contents(base_path('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);
|
$users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails);
|
||||||
$this->setPageTitle(trans('settings.users'));
|
$this->setPageTitle(trans('settings.users'));
|
||||||
$users->appends($listDetails);
|
$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');
|
$this->checkPermission('users-manage');
|
||||||
$authMethod = config('auth.method');
|
$authMethod = config('auth.method');
|
||||||
$roles = $this->userRepo->getAllRoles();
|
$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();
|
$activeSocialDrivers = $socialAuthService->getActiveDrivers();
|
||||||
$this->setPageTitle(trans('settings.user_profile'));
|
$this->setPageTitle(trans('settings.user_profile'));
|
||||||
$roles = $this->userRepo->getAllRoles();
|
$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);
|
$user = $this->userRepo->getById($id);
|
||||||
$this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name]));
|
$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)
|
public function showProfilePage($id)
|
||||||
{
|
{
|
||||||
$user = $this->userRepo->getById($id);
|
$user = $this->userRepo->getById($id);
|
||||||
|
|
||||||
$userActivity = $this->userRepo->getActivity($user);
|
$userActivity = $this->userRepo->getActivity($user);
|
||||||
$recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
|
$recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
|
||||||
$assetCounts = $this->userRepo->getAssetCounts($user);
|
$assetCounts = $this->userRepo->getAssetCounts($user);
|
||||||
return view('users/profile', [
|
|
||||||
|
return view('users.profile', [
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'activity' => $userActivity,
|
'activity' => $userActivity,
|
||||||
'recentlyCreated' => $recentlyCreated,
|
'recentlyCreated' => $recentlyCreated,
|
||||||
@ -251,19 +253,7 @@ class UserController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function switchBookView($id, Request $request)
|
public function switchBookView($id, Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermissionOr('users-manage', function () use ($id) {
|
return $this->switchViewType($id, $request, 'books');
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -274,18 +264,98 @@ class UserController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function switchShelfView($id, Request $request)
|
public function switchShelfView($id, Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermissionOr('users-manage', function () use ($id) {
|
return $this->switchViewType($id, $request, 'bookshelves');
|
||||||
return $this->currentUser->id == $id;
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* 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');
|
$viewType = $request->get('view_type');
|
||||||
if (!in_array($viewType, ['grid', 'list'])) {
|
if (!in_array($viewType, ['grid', 'list'])) {
|
||||||
$viewType = 'list';
|
$viewType = 'list';
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->userRepo->getById($id);
|
$user = $this->userRepo->getById($userId);
|
||||||
setting()->putUser($user, 'bookshelves_view_type', $viewType);
|
$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()) {
|
if ($request->ajax()) {
|
||||||
return response('Unauthorized.', 401);
|
return response('Unauthorized.', 401);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
use Blade;
|
use Blade;
|
||||||
use BookStack\Entities\Book;
|
use BookStack\Entities\Book;
|
||||||
use BookStack\Entities\Bookshelf;
|
use BookStack\Entities\Bookshelf;
|
||||||
|
use BookStack\Entities\BreadcrumbsViewComposer;
|
||||||
use BookStack\Entities\Chapter;
|
use BookStack\Entities\Chapter;
|
||||||
use BookStack\Entities\Page;
|
use BookStack\Entities\Page;
|
||||||
use BookStack\Settings\Setting;
|
use BookStack\Settings\Setting;
|
||||||
use BookStack\Settings\SettingService;
|
use BookStack\Settings\SettingService;
|
||||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Schema;
|
use Schema;
|
||||||
use Validator;
|
use Validator;
|
||||||
@ -33,7 +35,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
return substr_count($uploadName, '.') < 2;
|
return substr_count($uploadName, '.') < 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Custom blade view directives
|
// Custom blade view directives
|
||||||
Blade::directive('icon', function ($expression) {
|
Blade::directive('icon', function ($expression) {
|
||||||
return "<?php echo icon($expression); ?>";
|
return "<?php echo icon($expression); ?>";
|
||||||
@ -49,6 +50,9 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
'BookStack\\Chapter' => Chapter::class,
|
'BookStack\\Chapter' => Chapter::class,
|
||||||
'BookStack\\Page' => Page::class,
|
'BookStack\\Page' => Page::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// View Composers
|
||||||
|
View::composer('partials.breadcrumbs', BreadcrumbsViewComposer::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,20 +2,11 @@
|
|||||||
|
|
||||||
namespace BookStack\Providers;
|
namespace BookStack\Providers;
|
||||||
|
|
||||||
use BookStack\Actions\Activity;
|
|
||||||
use BookStack\Actions\ActivityService;
|
use BookStack\Actions\ActivityService;
|
||||||
use BookStack\Actions\View;
|
|
||||||
use BookStack\Actions\ViewService;
|
use BookStack\Actions\ViewService;
|
||||||
use BookStack\Auth\Permissions\PermissionService;
|
|
||||||
use BookStack\Settings\Setting;
|
|
||||||
use BookStack\Settings\SettingService;
|
use BookStack\Settings\SettingService;
|
||||||
use BookStack\Uploads\HttpFetcher;
|
|
||||||
use BookStack\Uploads\Image;
|
|
||||||
use BookStack\Uploads\ImageService;
|
use BookStack\Uploads\ImageService;
|
||||||
use Illuminate\Contracts\Cache\Repository;
|
|
||||||
use Illuminate\Contracts\Filesystem\Factory;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Intervention\Image\ImageManager;
|
|
||||||
|
|
||||||
class CustomFacadeProvider extends ServiceProvider
|
class CustomFacadeProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -37,34 +28,19 @@ class CustomFacadeProvider extends ServiceProvider
|
|||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->app->bind('activity', function () {
|
$this->app->bind('activity', function () {
|
||||||
return new ActivityService(
|
return $this->app->make(ActivityService::class);
|
||||||
$this->app->make(Activity::class),
|
|
||||||
$this->app->make(PermissionService::class)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('views', function () {
|
$this->app->bind('views', function () {
|
||||||
return new ViewService(
|
return $this->app->make(ViewService::class);
|
||||||
$this->app->make(View::class),
|
|
||||||
$this->app->make(PermissionService::class)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('setting', function () {
|
$this->app->bind('setting', function () {
|
||||||
return new SettingService(
|
return $this->app->make(SettingService::class);
|
||||||
$this->app->make(Setting::class),
|
|
||||||
$this->app->make(Repository::class)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('images', function () {
|
$this->app->bind('images', function () {
|
||||||
return new ImageService(
|
return $this->app->make(ImageService::class);
|
||||||
$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)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,23 @@ class SettingService
|
|||||||
*/
|
*/
|
||||||
public function getUser($user, $key, $default = false)
|
public function getUser($user, $key, $default = false)
|
||||||
{
|
{
|
||||||
|
if ($user->isDefault()) {
|
||||||
|
return session()->get($key, $default);
|
||||||
|
}
|
||||||
return $this->get($this->userKey($user->id, $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.
|
* Gets a setting value from the cache or database.
|
||||||
* Looks at the system defaults if not cached or in database.
|
* Looks at the system defaults if not cached or in database.
|
||||||
@ -180,6 +194,9 @@ class SettingService
|
|||||||
*/
|
*/
|
||||||
public function putUser($user, $key, $value)
|
public function putUser($user, $key, $value)
|
||||||
{
|
{
|
||||||
|
if ($user->isDefault()) {
|
||||||
|
return session()->put($key, $value);
|
||||||
|
}
|
||||||
return $this->put($this->userKey($user->id, $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.
|
* Check if current user is a signed in user.
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function signedInUser()
|
function signedInUser() : bool
|
||||||
{
|
{
|
||||||
return auth()->user() && !auth()->user()->isDefault();
|
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.
|
* Check if the current user has a permission.
|
||||||
* If an ownable element is passed in the jointPermissions are checked against
|
* If an ownable element is passed in the jointPermissions are checked against
|
||||||
|
2991
package-lock.json
generated
12
package.json
@ -13,17 +13,17 @@
|
|||||||
"@babel/core": "^7.1.6",
|
"@babel/core": "^7.1.6",
|
||||||
"@babel/polyfill": "^7.0.0",
|
"@babel/polyfill": "^7.0.0",
|
||||||
"@babel/preset-env": "^7.1.6",
|
"@babel/preset-env": "^7.1.6",
|
||||||
"autoprefixer": "^8.6.5",
|
"autoprefixer": "^9.4.7",
|
||||||
"babel-loader": "^8.0.4",
|
"babel-loader": "^8.0.4",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^2.1.0",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
|
||||||
"livereload": "^0.7.0",
|
"livereload": "^0.7.0",
|
||||||
|
"mini-css-extract-plugin": "^0.5.0",
|
||||||
"node-sass": "^4.10.0",
|
"node-sass": "^4.10.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss-loader": "^2.1.6",
|
"postcss-loader": "^3.0.0",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^0.21.0",
|
"style-loader": "^0.23.1",
|
||||||
"uglifyjs-webpack-plugin": "^1.3.0",
|
"uglifyjs-webpack-plugin": "^2.1.1",
|
||||||
"webpack": "^4.26.1",
|
"webpack": "^4.26.1",
|
||||||
"webpack-cli": "^3.1.2"
|
"webpack-cli": "^3.1.2"
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1 @@
|
|||||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/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>
|
||||||
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
|
||||||
<path d="M0 0h24v24H0z" fill="none"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 166 B |
71
resources/assets/icons/books.svg
Normal file
@ -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 |
1
resources/assets/icons/check.svg
Normal file
@ -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 |
1
resources/assets/icons/chevron-right.svg
Normal file
@ -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 |
1
resources/assets/icons/sort-down.svg
Normal file
@ -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 |
1
resources/assets/icons/sort-up.svg
Normal file
@ -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 |
58
resources/assets/js/components/breadcrumb-listing.js
Normal file
@ -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) {
|
constructor(elem) {
|
||||||
this.container = elem;
|
this.container = elem;
|
||||||
this.menu = elem.querySelector('ul');
|
this.menu = elem.querySelector('ul, [dropdown-menu]');
|
||||||
this.toggle = elem.querySelector('[dropdown-toggle]');
|
this.toggle = elem.querySelector('[dropdown-toggle]');
|
||||||
this.setupListeners();
|
this.setupListeners();
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,17 @@ class EntitySelector {
|
|||||||
this.elem = elem;
|
this.elem = elem;
|
||||||
this.search = '';
|
this.search = '';
|
||||||
this.lastClick = 0;
|
this.lastClick = 0;
|
||||||
|
this.selectedItemData = null;
|
||||||
|
|
||||||
let entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
|
const entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
|
||||||
let entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
|
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.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}&permission=${encodeURIComponent(entityPermission)}`);
|
||||||
|
|
||||||
this.input = elem.querySelector('[entity-selector-input]');
|
this.input = elem.querySelector('[entity-selector-input]');
|
||||||
this.searchInput = elem.querySelector('[entity-selector-search]');
|
this.searchInput = elem.querySelector('[entity-selector-search]');
|
||||||
this.loading = elem.querySelector('[entity-selector-loading]');
|
this.loading = elem.querySelector('[entity-selector-loading]');
|
||||||
this.resultsContainer = elem.querySelector('[entity-selector-results]');
|
this.resultsContainer = elem.querySelector('[entity-selector-results]');
|
||||||
|
this.addButton = elem.querySelector('[entity-selector-add-button]');
|
||||||
|
|
||||||
this.elem.addEventListener('click', this.onClick.bind(this));
|
this.elem.addEventListener('click', this.onClick.bind(this));
|
||||||
|
|
||||||
@ -26,10 +28,20 @@ class EntitySelector {
|
|||||||
this.searchEntities(this.searchInput.value);
|
this.searchEntities(this.searchInput.value);
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.searchInput.addEventListener('keydown', event => {
|
this.searchInput.addEventListener('keydown', event => {
|
||||||
if (event.keyCode === 13) event.preventDefault();
|
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.showLoading();
|
||||||
this.initialLoad();
|
this.initialLoad();
|
||||||
}
|
}
|
||||||
@ -53,7 +65,7 @@ class EntitySelector {
|
|||||||
|
|
||||||
searchEntities(searchTerm) {
|
searchEntities(searchTerm) {
|
||||||
this.input.value = '';
|
this.input.value = '';
|
||||||
let url = this.searchUrl + `&term=${encodeURIComponent(searchTerm)}`;
|
let url = `${this.searchUrl}&term=${encodeURIComponent(searchTerm)}`;
|
||||||
window.$http.get(url).then(resp => {
|
window.$http.get(url).then(resp => {
|
||||||
this.resultsContainer.innerHTML = resp.data;
|
this.resultsContainer.innerHTML = resp.data;
|
||||||
this.hideLoading();
|
this.hideLoading();
|
||||||
@ -68,49 +80,54 @@ class EntitySelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
let t = event.target;
|
const listItem = event.target.closest('[data-entity-type]');
|
||||||
|
if (listItem) {
|
||||||
if (t.matches('.entity-list-item *')) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
let item = t.closest('[data-entity-type]');
|
this.selectItem(listItem);
|
||||||
this.selectItem(item);
|
|
||||||
} else if (t.matches('[data-entity-type]')) {
|
|
||||||
this.selectItem(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectItem(item) {
|
selectItem(item) {
|
||||||
let isDblClick = this.isDoubleClick();
|
const isDblClick = this.isDoubleClick();
|
||||||
let type = item.getAttribute('data-entity-type');
|
const type = item.getAttribute('data-entity-type');
|
||||||
let id = item.getAttribute('data-entity-id');
|
const id = item.getAttribute('data-entity-id');
|
||||||
let isSelected = !item.classList.contains('selected') || isDblClick;
|
const isSelected = (!item.classList.contains('selected') || isDblClick);
|
||||||
|
|
||||||
this.unselectAll();
|
this.unselectAll();
|
||||||
this.input.value = isSelected ? `${type}:${id}` : '';
|
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) {
|
if (isSelected) {
|
||||||
item.classList.add('selected');
|
item.classList.add('selected');
|
||||||
item.classList.add('primary-background');
|
this.selectedItemData = data;
|
||||||
|
} else {
|
||||||
|
window.$events.emit('entity-select-change', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDblClick && !isSelected) return;
|
if (!isDblClick && !isSelected) return;
|
||||||
|
|
||||||
let link = item.querySelector('.entity-list-item-link').getAttribute('href');
|
if (isDblClick) {
|
||||||
let name = item.querySelector('.entity-list-item-name').textContent;
|
this.confirmSelection(data);
|
||||||
let data = {id: Number(id), name: name, link: link};
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
window.$events.emit('entity-select-change', data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isDblClick) window.$events.emit('entity-select-confirm', data);
|
confirmSelection(data) {
|
||||||
if (isSelected) window.$events.emit('entity-select-change', data);
|
window.$events.emit('entity-select-confirm', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
unselectAll() {
|
unselectAll() {
|
||||||
let selected = this.elem.querySelectorAll('.selected');
|
let selected = this.elem.querySelectorAll('.selected');
|
||||||
for (let i = 0, len = selected.length; i < len; i++) {
|
for (let selectedElem of selected) {
|
||||||
selected[i].classList.remove('selected');
|
selectedElem.classList.remove('selected', 'primary-background');
|
||||||
selected[i].classList.remove('primary-background');
|
|
||||||
}
|
}
|
||||||
|
this.selectedItemData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,13 @@ class ExpandToggle {
|
|||||||
|
|
||||||
constructor(elem) {
|
constructor(elem) {
|
||||||
this.elem = 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');
|
this.selector = elem.getAttribute('expand-toggle');
|
||||||
|
|
||||||
|
// Listener setup
|
||||||
elem.addEventListener('click', this.click.bind(this));
|
elem.addEventListener('click', this.click.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +58,20 @@ class ExpandToggle {
|
|||||||
|
|
||||||
click(event) {
|
click(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let matchingElems = document.querySelectorAll(this.selector);
|
|
||||||
for (let i = 0, len = matchingElems.length; i < len; i++) {
|
const matchingElems = document.querySelectorAll(this.selector);
|
||||||
this.isOpen ? this.close(matchingElems[i]) : this.open(matchingElems[i]);
|
for (let match of matchingElems) {
|
||||||
|
this.isOpen ? this.close(match) : this.open(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isOpen = !this.isOpen;
|
this.isOpen = !this.isOpen;
|
||||||
|
this.updateSystemAjax(this.isOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSystemAjax(isOpen) {
|
||||||
|
window.$http.patch(this.updateEndpoint, {
|
||||||
|
expand: isOpen ? 'true' : 'false'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
31
resources/assets/js/components/header-mobile-toggle.js
Normal file
@ -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 pageDisplay from "./page-display";
|
||||||
import shelfSort from "./shelf-sort";
|
import shelfSort from "./shelf-sort";
|
||||||
import homepageControl from "./homepage-control";
|
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 = {
|
const componentMapping = {
|
||||||
'dropdown': dropdown,
|
'dropdown': dropdown,
|
||||||
@ -41,6 +45,11 @@ const componentMapping = {
|
|||||||
'page-display': pageDisplay,
|
'page-display': pageDisplay,
|
||||||
'shelf-sort': shelfSort,
|
'shelf-sort': shelfSort,
|
||||||
'homepage-control': homepageControl,
|
'homepage-control': homepageControl,
|
||||||
|
'header-mobile-toggle': headerMobileToggle,
|
||||||
|
'list-sort-control': listSortControl,
|
||||||
|
'tri-layout': triLayout,
|
||||||
|
'breadcrumb-listing': breadcrumbListing,
|
||||||
|
'permissions-table': permissionsTable,
|
||||||
};
|
};
|
||||||
|
|
||||||
window.components = {};
|
window.components = {};
|
||||||
@ -79,4 +88,4 @@ function initAll(parentElement) {
|
|||||||
|
|
||||||
window.components.init = initAll;
|
window.components.init = initAll;
|
||||||
|
|
||||||
export default initAll;
|
export default initAll;
|
||||||
|
42
resources/assets/js/components/list-sort-control.js
Normal file
@ -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();
|
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 => {
|
window.$events.listen('editor-markdown-update', value => {
|
||||||
this.cm.setValue(value);
|
this.cm.setValue(value);
|
||||||
this.updateAndRender();
|
this.updateAndRender();
|
||||||
|
@ -6,7 +6,7 @@ class Overlay {
|
|||||||
elem.addEventListener('click', event => {
|
elem.addEventListener('click', event => {
|
||||||
if (event.target === elem) return this.hide();
|
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++) {
|
for (let i=0; i < closeButtons.length; i++) {
|
||||||
closeButtons[i].addEventListener('click', this.hide.bind(this));
|
closeButtons[i].addEventListener('click', this.hide.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class PageComments {
|
|||||||
commentElem.querySelector('[comment-edit-container]').style.display = 'block';
|
commentElem.querySelector('[comment-edit-container]').style.display = 'block';
|
||||||
let textArea = commentElem.querySelector('[comment-edit-container] textarea');
|
let textArea = commentElem.querySelector('[comment-edit-container] textarea');
|
||||||
let lineCount = textArea.value.split('\n').length;
|
let lineCount = textArea.value.split('\n').length;
|
||||||
textArea.style.height = (lineCount * 20) + 'px';
|
textArea.style.height = ((lineCount * 20) + 40) + 'px';
|
||||||
this.editingComment = commentElem;
|
this.editingComment = commentElem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +88,7 @@ class PageComments {
|
|||||||
commentElem.parentNode.removeChild(commentElem);
|
commentElem.parentNode.removeChild(commentElem);
|
||||||
window.$events.emit('success', window.trans('entities.comment_deleted_success'));
|
window.$events.emit('success', window.trans('entities.comment_deleted_success'));
|
||||||
this.updateCount();
|
this.updateCount();
|
||||||
|
this.hideForm();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ class PageComments {
|
|||||||
showForm() {
|
showForm() {
|
||||||
this.formContainer.style.display = 'block';
|
this.formContainer.style.display = 'block';
|
||||||
this.formContainer.parentNode.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();
|
this.formInput.focus();
|
||||||
window.scrollToElement(this.formInput);
|
window.scrollToElement(this.formInput);
|
||||||
}
|
}
|
||||||
@ -137,7 +138,18 @@ class PageComments {
|
|||||||
hideForm() {
|
hideForm() {
|
||||||
this.formContainer.style.display = 'none';
|
this.formContainer.style.display = 'none';
|
||||||
this.formContainer.parentNode.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) {
|
setReply(commentElem) {
|
||||||
|
@ -208,8 +208,8 @@ class PageDisplay {
|
|||||||
let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
|
let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
|
||||||
|
|
||||||
// observe each heading
|
// observe each heading
|
||||||
for (let i = 0; i !== headings.length; ++i) {
|
for (let heading of headings) {
|
||||||
pageNavObserver.observe(headings[i]);
|
pageNavObserver.observe(heading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,14 +221,9 @@ class PageDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleAnchorHighlighting(elementId, shouldHighlight) {
|
function toggleAnchorHighlighting(elementId, shouldHighlight) {
|
||||||
let anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
|
const anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
|
||||||
for (let i = 0; i < anchorsToHighlight.length; i++) {
|
for (let anchor of anchorsToHighlight) {
|
||||||
// Change below to use classList.toggle when IE support is dropped.
|
anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
|
||||||
if (shouldHighlight) {
|
|
||||||
anchorsToHighlight[i].classList.add('current-heading');
|
|
||||||
} else {
|
|
||||||
anchorsToHighlight[i].classList.remove('current-heading');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
resources/assets/js/components/permissions-table.js
Normal file
@ -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) {
|
constructor(elem) {
|
||||||
this.elem = 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) {
|
onClick(event) {
|
||||||
let checked = this.input.value !== 'true';
|
let checked = this.checkbox.checked;
|
||||||
this.input.value = checked ? 'true' : 'false';
|
this.input.value = checked ? 'true' : 'false';
|
||||||
checked ? this.elem.classList.add('active') : this.elem.classList.remove('active');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
95
resources/assets/js/components/tri-layout.js
Normal file
@ -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,
|
plugins: this.plugins,
|
||||||
imagetools_toolbar: 'imageoptions',
|
imagetools_toolbar: 'imageoptions',
|
||||||
toolbar: this.getToolBar(),
|
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: [
|
style_formats: [
|
||||||
{title: "Header Large", format: "h2"},
|
{title: "Header Large", format: "h2"},
|
||||||
{title: "Header Medium", format: "h3"},
|
{title: "Header Medium", format: "h3"},
|
||||||
@ -517,6 +517,16 @@ class WysiwygEditor {
|
|||||||
if (scrollId) {
|
if (scrollId) {
|
||||||
scrollToText(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() {
|
function editorChange() {
|
||||||
@ -600,6 +610,7 @@ class WysiwygEditor {
|
|||||||
|
|
||||||
// Paste image-uploads
|
// Paste image-uploads
|
||||||
editor.on('paste', event => editorPaste(event, editor, context));
|
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 {
|
@keyframes loadingBob {
|
||||||
0% {
|
0% {
|
||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
@ -89,8 +69,4 @@
|
|||||||
animation-duration: 180ms;
|
animation-duration: 180ms;
|
||||||
animation-delay: 0s;
|
animation-delay: 0s;
|
||||||
animation-timing-function: cubic-bezier(.62, .28, .23, .99);
|
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
|
* Callouts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.callout {
|
.callout {
|
||||||
border-left: 3px solid #BBB;
|
border-left: 3px solid #BBB;
|
||||||
background-color: #EEE;
|
background-color: #EEE;
|
||||||
@ -182,19 +53,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card-style blocks
|
||||||
|
*/
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
margin: $-m;
|
|
||||||
background-color: #FFF;
|
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 {
|
h3 {
|
||||||
padding: $-m;
|
padding: $-m $-m $-xs;
|
||||||
border-bottom: 1px solid #E8E8E8;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: $fs-s;
|
font-size: $fs-m;
|
||||||
color: #888;
|
color: #222;
|
||||||
fill: #888;
|
fill: #222;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
}
|
||||||
h3 a {
|
h3 a {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@ -208,18 +82,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar .card {
|
|
||||||
h3, .body, .empty-text {
|
|
||||||
padding: $-s $-m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.drag-card {
|
.card.drag-card {
|
||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0;
|
padding: 0 0 0 ($-s + 28px);
|
||||||
padding-left: $-s + 28px;
|
|
||||||
margin: $-s 0;
|
margin: $-s 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
.drag-card-action {
|
.drag-card-action {
|
||||||
@ -227,14 +94,12 @@
|
|||||||
}
|
}
|
||||||
.handle, .drag-card-action {
|
.handle, .drag-card-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
padding-left: $-xs;
|
padding: 0 $-xs;
|
||||||
padding-right: $-xs;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #EEE;
|
background-color: #EEE;
|
||||||
}
|
}
|
||||||
@ -246,9 +111,6 @@
|
|||||||
margin: $-s 0;
|
margin: $-s 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
> div.padded {
|
|
||||||
padding: $-s 0 !important;
|
|
||||||
}
|
|
||||||
.handle {
|
.handle {
|
||||||
background-color: #EEE;
|
background-color: #EEE;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -263,12 +125,89 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.well {
|
.grid-card {
|
||||||
background-color: #F8F8F8;
|
display: flex;
|
||||||
padding: $-m;
|
flex-direction: column;
|
||||||
border: 1px solid #DDD;
|
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 {
|
.tag-item {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
margin-bottom: $-xs;
|
margin-bottom: $-xs;
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
|
button {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin generate-button-colors($textColor, $backgroundColor) {
|
@mixin generate-button-colors($textColor, $backgroundColor) {
|
||||||
background-color: $backgroundColor;
|
background-color: $backgroundColor;
|
||||||
color: $textColor;
|
color: $textColor;
|
||||||
fill: $textColor;
|
fill: $textColor;
|
||||||
text-transform: uppercase;
|
|
||||||
border: 1px solid $backgroundColor;
|
border: 1px solid $backgroundColor;
|
||||||
vertical-align: top;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: lighten($backgroundColor, 8%);
|
background-color: lighten($backgroundColor, 8%);
|
||||||
//box-shadow: $bs-med;
|
|
||||||
text-decoration: none;
|
|
||||||
color: $textColor;
|
color: $textColor;
|
||||||
}
|
}
|
||||||
&:active {
|
&:active {
|
||||||
@ -18,7 +17,6 @@
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: lighten($backgroundColor, 4%);
|
background-color: lighten($backgroundColor, 4%);
|
||||||
box-shadow: $bs-light;
|
box-shadow: $bs-light;
|
||||||
text-decoration: none;
|
|
||||||
color: $textColor;
|
color: $textColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,42 +24,36 @@
|
|||||||
// Button Specific Variables
|
// Button Specific Variables
|
||||||
$button-border-radius: 2px;
|
$button-border-radius: 2px;
|
||||||
|
|
||||||
.button-base {
|
.button {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: $fs-m;
|
font-size: 0.85rem;
|
||||||
line-height: 1.4em;
|
line-height: 1.4em;
|
||||||
padding: $-xs*1.3 $-m;
|
padding: $-xs*1.3 $-m;
|
||||||
margin: $-xs $-xs $-xs 0;
|
margin-top: $-xs;
|
||||||
|
margin-bottom: $-xs;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: none;
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
border-radius: $button-border-radius;
|
border-radius: $button-border-radius;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all ease-in-out 120ms;
|
transition: background-color ease-in-out 120ms, box-shadow ease-in-out 120ms;
|
||||||
box-shadow: 0;
|
box-shadow: none;
|
||||||
@include generate-button-colors(#EEE, $primary);
|
background-color: $primary;
|
||||||
}
|
color: #FFF;
|
||||||
|
fill: #FFF;
|
||||||
.button, input[type="button"], input[type="submit"] {
|
text-transform: uppercase;
|
||||||
@extend .button-base;
|
border: 1px solid $primary;
|
||||||
&.pos {
|
vertical-align: top;
|
||||||
@include generate-button-colors(#EEE, $positive);
|
&:hover, &:focus {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
&.neg {
|
&:active {
|
||||||
@include generate-button-colors(#EEE, $negative);
|
background-color: darken($primary, 8%);
|
||||||
}
|
|
||||||
&.secondary {
|
|
||||||
@include generate-button-colors(#EEE, $secondary);
|
|
||||||
}
|
|
||||||
&.muted {
|
|
||||||
@include generate-button-colors(#EEE, #AAA);
|
|
||||||
}
|
|
||||||
&.muted-light {
|
|
||||||
@include generate-button-colors(#666, #e4e4e4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.button.primary {
|
||||||
|
@include generate-button-colors(#FFFFFF, $primary);
|
||||||
|
}
|
||||||
.button.outline {
|
.button.outline {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: #888;
|
color: #888;
|
||||||
@ -71,78 +63,38 @@ $button-border-radius: 2px;
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background-color: #EEE;
|
background-color: #EEE;
|
||||||
}
|
}
|
||||||
&.page {
|
}
|
||||||
border-color: $color-page;
|
|
||||||
color: $color-page;
|
.button + .button {
|
||||||
fill: $color-page;
|
margin-left: $-s;
|
||||||
&:hover, &:focus, &:active {
|
}
|
||||||
background-color: $color-page;
|
|
||||||
color: #FFF;
|
.button.small {
|
||||||
fill: #FFF;
|
font-size: 0.75rem;
|
||||||
}
|
padding: $-xs*1.2 $-s;
|
||||||
}
|
|
||||||
&.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-button {
|
.text-button {
|
||||||
@extend .link;
|
cursor: pointer;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.4em;
|
||||||
&:focus, &:active {
|
&:focus, &:active {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
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 {
|
.button.block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
display: block;
|
display: block;
|
||||||
&.text-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.icon {
|
.button.icon {
|
||||||
@ -160,9 +112,7 @@ $button-border-radius: 2px;
|
|||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
padding: $-s $-m;
|
padding: $-s $-m ($-s - 2px) ($-m*2 + 24px);
|
||||||
padding-bottom: $-s - 2px;
|
|
||||||
padding-left: $-m*2 + 24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button[disabled] {
|
.button[disabled] {
|
||||||
|
72
resources/assets/sass/_colors.scss
Normal file
@ -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;
|
transition: all ease-in-out 180ms;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
svg[data-icon="caret-right"] {
|
svg[data-icon="caret-right"] {
|
||||||
|
margin-right: 0;
|
||||||
|
font-size: 1rem;
|
||||||
transition: all ease-in-out 180ms;
|
transition: all ease-in-out 180ms;
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
transform-origin: 25% 50%;
|
transform-origin: 50% 50%;
|
||||||
}
|
}
|
||||||
&.open svg[data-icon="caret-right"] {
|
&.open svg[data-icon="caret-right"] {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
svg[data-icon="caret-right"] + * {
|
||||||
|
margin-left: $-xs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[overlay] {
|
[overlay] {
|
||||||
@ -110,7 +115,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.corner-button {
|
.popup-footer button, .popup-header-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -118,6 +123,16 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-shadow: none;
|
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 {
|
.popup-header, .popup-footer {
|
||||||
@ -130,6 +145,9 @@
|
|||||||
padding: 8px $-m;
|
padding: 8px $-m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.popup-footer {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||||
height: 444px;
|
height: 444px;
|
||||||
min-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 {
|
#entity-selector-wrap .popup-body .form-group {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.popup-body .entity-selector-container {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.image-manager-body {
|
.image-manager-body {
|
||||||
min-height: 70vh;
|
min-height: 70vh;
|
||||||
@ -583,27 +604,26 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.comment-box {
|
.comment-box {
|
||||||
clear: left;
|
|
||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
margin-bottom: $-s;
|
border-radius: 4px;
|
||||||
border-radius: 3px;
|
background-color: #FFF;
|
||||||
.content {
|
.content {
|
||||||
padding: $-s;
|
|
||||||
font-size: 0.666em;
|
font-size: 0.666em;
|
||||||
p, ul, ol {
|
p, ul, ol {
|
||||||
font-size: $fs-m;
|
font-size: $fs-m;
|
||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.reply-row {
|
.actions {
|
||||||
padding: $-xs $-s;
|
opacity: 0;
|
||||||
|
transition: opacity ease-in-out 120ms;
|
||||||
|
}
|
||||||
|
&:hover .actions {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-box .header {
|
.comment-box .header {
|
||||||
padding: $-xs $-s;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
border-bottom: 1px solid #DDD;
|
|
||||||
.meta {
|
.meta {
|
||||||
img, a, span {
|
img, a, span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -626,4 +646,11 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
|||||||
|
|
||||||
#tag-manager .drag-card {
|
#tag-manager .drag-card {
|
||||||
max-width: 500px;
|
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 {
|
.markdown-display {
|
||||||
padding: 0 $-m 0;
|
padding: 0 $-m 0;
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
@ -98,7 +126,7 @@ label {
|
|||||||
line-height: 1.4em;
|
line-height: 1.4em;
|
||||||
font-size: 0.94em;
|
font-size: 0.94em;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #999;
|
color: #666;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
margin-bottom: 0.2em;
|
margin-bottom: 0.2em;
|
||||||
&.inline {
|
&.inline {
|
||||||
@ -139,56 +167,77 @@ input[type=date] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.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;
|
user-select: none;
|
||||||
&:after {
|
display: inline-grid;
|
||||||
content: '';
|
grid-template-columns: (16px + $-s) 1fr;
|
||||||
display: block;
|
align-items: center;
|
||||||
position: relative;
|
margin: $-m 0;
|
||||||
left: 0;
|
.custom-checkbox {
|
||||||
margin-top: -3px;
|
width: 16px;
|
||||||
width: 20px;
|
height: 16px;
|
||||||
height: 20px;
|
border-radius: 2px;
|
||||||
border-radius: 50%;
|
display: inline-block;
|
||||||
background-color: #fafafa;
|
border: 2px solid currentColor;
|
||||||
border: 1px solid #CCC;
|
opacity: 0.6;
|
||||||
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);
|
overflow: hidden;
|
||||||
transition: all ease-in-out 120ms;
|
fill: currentColor;
|
||||||
}
|
.svg-icon {
|
||||||
&.active {
|
width: 100%;
|
||||||
background-color: rgba($positive, 0.4);
|
height: 100%;
|
||||||
&:after {
|
margin: 0;
|
||||||
left: 16px;
|
bottom: auto;
|
||||||
background-color: $positive;
|
top: -1.5px;
|
||||||
border: darken($positive, 20%);
|
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 {
|
.toggle-switch-list {
|
||||||
display: none;
|
.toggle-switch {
|
||||||
}
|
margin: $-xs 0;
|
||||||
input:checked + .toggle-switch {
|
}
|
||||||
background-color: rgba($positive, 0.4);
|
&.compact .toggle-switch {
|
||||||
&:after {
|
margin: 1px 0;
|
||||||
left: 16px;
|
|
||||||
background-color: $positive;
|
|
||||||
border: darken($positive, 20%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: $-s;
|
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%;
|
width: 100%;
|
||||||
min-height: 64px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,6 +246,8 @@ input:checked + .toggle-switch {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
@ -206,11 +257,9 @@ input:checked + .toggle-switch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.form-group[collapsible] {
|
.form-group[collapsible] {
|
||||||
margin-left: -$-m;
|
|
||||||
margin-right: -$-m;
|
|
||||||
padding: 0 $-m;
|
padding: 0 $-m;
|
||||||
border-top: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
border-bottom: 1px solid #DDD;
|
border-radius: 4px;
|
||||||
.collapse-title {
|
.collapse-title {
|
||||||
margin-left: -$-m;
|
margin-left: -$-m;
|
||||||
margin-right: -$-m;
|
margin-right: -$-m;
|
||||||
@ -238,9 +287,6 @@ input:checked + .toggle-switch {
|
|||||||
&.open .collapse-title label:before {
|
&.open .collapse-title label:before {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
&+.form-group[collapsible] {
|
|
||||||
margin-top: -($-s + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline-input-style {
|
.inline-input-style {
|
||||||
@ -304,6 +350,13 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
|
|||||||
width: 300px;
|
width: 300px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
&.flexible input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.search-box-cancel {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.outline > input {
|
.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 {
|
.image-picker img {
|
||||||
background-color: #BBB;
|
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.
|
* 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 {
|
header {
|
||||||
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
z-index: 2;
|
z-index: 6;
|
||||||
top: 0;
|
top: 0;
|
||||||
background-color: $primary-dark;
|
background-color: $primary-dark;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
.padded {
|
|
||||||
padding: $-m;
|
|
||||||
}
|
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
|
box-shadow: $bs-card;
|
||||||
|
padding: $-xxs 0;
|
||||||
.links {
|
.links {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-left: $-m;
|
|
||||||
}
|
}
|
||||||
.links a {
|
.links a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -28,15 +38,6 @@ header {
|
|||||||
padding-left: $-m;
|
padding-left: $-m;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
@include smaller-than($screen-md) {
|
|
||||||
.links a {
|
|
||||||
padding-left: $-s;
|
|
||||||
padding-right: $-s;
|
|
||||||
}
|
|
||||||
.dropdown-container {
|
|
||||||
padding-left: $-s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.avatar, .user-name {
|
.avatar, .user-name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@ -63,27 +64,17 @@ header {
|
|||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
@include smaller-than($screen-md) {
|
@include between($l, $xl) {
|
||||||
padding-left: $-xs;
|
padding-left: $-xs;
|
||||||
.name {
|
.name {
|
||||||
display: none;
|
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 {
|
.header-search {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@ -92,13 +83,16 @@ header .search-box {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
input {
|
input {
|
||||||
background-color: rgba(0, 0, 0, 0.2);
|
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;
|
color: #EEE;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
padding-left: 40px;
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
fill: #EEE;
|
fill: #EEE;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
left: 16px;
|
||||||
svg {
|
svg {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
@ -115,20 +109,11 @@ header .search-box {
|
|||||||
:-moz-placeholder { /* Firefox 18- */
|
:-moz-placeholder { /* Firefox 18- */
|
||||||
color: #DDD;
|
color: #DDD;
|
||||||
}
|
}
|
||||||
@include smaller-than($screen-lg) {
|
@include between($l, $xl) {
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
@include smaller-than($l) {
|
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($s) {
|
|
||||||
.header-search {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -151,10 +136,184 @@ header .search-box {
|
|||||||
height: 43px;
|
height: 43px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumbs span.sep {
|
.mobile-menu-toggle {
|
||||||
color: #aaa;
|
color: #FFF;
|
||||||
|
fill: #FFF;
|
||||||
|
font-size: 2em;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||||
|
border-radius: 4px;
|
||||||
padding: 0 $-xs;
|
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 {
|
.faded {
|
||||||
a, button, span, span > div {
|
a, button, span, span > div {
|
||||||
color: #666;
|
color: #666;
|
||||||
@ -175,20 +334,9 @@ header .search-box {
|
|||||||
padding: $-s;
|
padding: $-s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.faded-small {
|
.action-buttons .text-button {
|
||||||
color: #000;
|
|
||||||
fill: #000;
|
|
||||||
font-size: 0.9em;
|
|
||||||
background-color: $primary-faded;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-container {
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumbs .text-button, .action-buttons .text-button {
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: $-s;
|
padding: $-xs $-s;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
@ -217,28 +365,12 @@ header .search-box {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($m) {
|
@include smaller-than($m) {
|
||||||
.breadcrumbs .text-button, .action-buttons .text-button {
|
.action-buttons .text-button {
|
||||||
padding: $-xs $-xs;
|
padding: $-xs $-xs;
|
||||||
}
|
}
|
||||||
.action-buttons .dropdown-container:last-child a {
|
.action-buttons .dropdown-container:last-child a {
|
||||||
padding-left: $-xs;
|
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 {
|
.nav-tabs {
|
||||||
@ -253,7 +385,4 @@ header .search-box {
|
|||||||
border-bottom: 2px solid $primary;
|
border-bottom: 2px solid $primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.faded-small .nav-tabs a {
|
|
||||||
padding: $-s $-m;
|
|
||||||
}
|
}
|
@ -3,27 +3,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background-color: #FFFFFF;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
background-color: #F2F2F2;
|
||||||
&.flexbox {
|
&.flexbox {
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
&.shaded {
|
|
||||||
background-color: #F2F2F2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-size: $fs-m;
|
font-size: $fs-m;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: #616161;
|
color: #444;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
&.shaded {
|
background-color: #F2F2F2;
|
||||||
background-color: #F2F2F2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-size: 100%;
|
|
||||||
}
|
}
|
312
resources/assets/sass/_layout.scss
Normal file
@ -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 {
|
.book-contents .entity-list-item {
|
||||||
margin: $-l 0 $-xs 0;
|
.icon {
|
||||||
font-size: 1.666em;
|
width: 4px;
|
||||||
|
border-radius: 1px;
|
||||||
|
justify-self: stretch;
|
||||||
|
align-self: stretch;
|
||||||
|
height: auto;
|
||||||
|
margin-right: $-l;
|
||||||
}
|
}
|
||||||
a.chapter {
|
.icon:after {
|
||||||
color: $color-chapter;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
.inset-list {
|
.icon svg {
|
||||||
display: none;
|
display: none;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
h5 {
|
p {
|
||||||
display: block;
|
margin-bottom: 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.entity-list-item {
|
.inner-page {
|
||||||
margin-bottom: $-m;
|
padding-top: 0;
|
||||||
}
|
padding-bottom: 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($s) {
|
.entity-list-item + .chapter-expansion {
|
||||||
.page-list h4 {
|
display: flex;
|
||||||
font-size: 1.333em;
|
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 {
|
.sidebar-page-nav {
|
||||||
$nav-indent: $-s;
|
$nav-indent: $-m;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: $-s 0 $-m 2px;
|
margin: $-s 0 $-m $-xs;
|
||||||
border-left: 2px dotted #BBB;
|
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 {
|
li {
|
||||||
padding-left: $-s;
|
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.h1 {
|
.h1 {
|
||||||
margin-left: -2px;
|
padding-left: $nav-indent;
|
||||||
}
|
}
|
||||||
.h2 {
|
.h2 {
|
||||||
margin-left: -2px;
|
padding-left: $nav-indent;
|
||||||
}
|
}
|
||||||
.h3 {
|
.h3 {
|
||||||
margin-left: $nav-indent;
|
padding-left: $nav-indent * 2;
|
||||||
}
|
}
|
||||||
.h4 {
|
.h4 {
|
||||||
margin-left: $nav-indent*2;
|
padding-left: $nav-indent * 2.5;
|
||||||
}
|
}
|
||||||
.h5 {
|
.h5 {
|
||||||
margin-left: $nav-indent*3;
|
padding-left: $nav-indent*3;
|
||||||
}
|
}
|
||||||
.h6 {
|
.h6 {
|
||||||
margin-left: $nav-indent*4;
|
padding-left: $nav-indent*3.5;
|
||||||
}
|
}
|
||||||
.current-heading {
|
.current-heading {
|
||||||
font-weight: bold;
|
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
|
// Sidebar list
|
||||||
.book-tree {
|
.book-tree .sidebar-page-list {
|
||||||
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 {
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: $-xs 0 0;
|
margin: $-xs -$-s 0 -$-s;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
border-left: 5px solid $color-book;
|
padding-right: 0;
|
||||||
li a {
|
position: relative;
|
||||||
|
|
||||||
|
&:after, .sub-menu:after {
|
||||||
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
border-bottom: none;
|
position: absolute;
|
||||||
padding: $-xs 0 $-xs $-s;
|
left: $-m;
|
||||||
&:hover {
|
top: 1rem;
|
||||||
text-decoration: none;
|
bottom: 1rem;
|
||||||
}
|
border-left: 4px solid rgba(0, 0, 0, 0.1);
|
||||||
}
|
z-index: 0;
|
||||||
li a i {
|
|
||||||
padding-right: $-xs + 2px;
|
|
||||||
}
|
|
||||||
li, a {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
a.bold {
|
|
||||||
color: #EEE !important;
|
|
||||||
fill: #EEE !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
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;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.book {
|
.chapter-child-menu {
|
||||||
color: $color-book !important;
|
font-size: .8rem;
|
||||||
fill: $color-book !important;
|
margin-top: -.2rem;
|
||||||
&.selected {
|
margin-left: -1rem;
|
||||||
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-toggle] {
|
[chapter-toggle] {
|
||||||
padding-left: $-s;
|
padding-left: .7rem;
|
||||||
|
padding-bottom: .2rem;
|
||||||
}
|
}
|
||||||
.list-item-chapter {
|
.entity-list-item .icon {
|
||||||
border-left: 5px solid $color-chapter;
|
z-index: 2;
|
||||||
margin: 10px 10px;
|
width: 4px;
|
||||||
display: block;
|
height: auto;
|
||||||
|
align-self: stretch;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 1px;
|
||||||
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
.list-item-page {
|
.entity-list-item .icon:after {
|
||||||
border-bottom: none;
|
opacity: 1;
|
||||||
border-left: 5px solid $color-page;
|
|
||||||
margin: 10px 10px;
|
|
||||||
}
|
}
|
||||||
.list-item-page.draft {
|
.entity-list-item .icon svg {
|
||||||
border-left: 5px solid $color-page-draft;
|
display: none;
|
||||||
}
|
}
|
||||||
.page.draft .page, .list-item-page.draft a.page {
|
}
|
||||||
color: $color-page-draft !important;
|
|
||||||
fill: $color-page-draft !important;
|
.chapter-child-menu {
|
||||||
}
|
ul.sub-menu {
|
||||||
.sub-menu {
|
|
||||||
display: none;
|
display: none;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
[chapter-toggle].open + .sub-menu {
|
[chapter-toggle].open + .sub-menu {
|
||||||
display: block;
|
display: block;
|
||||||
@ -186,26 +221,41 @@
|
|||||||
// Sortable Lists
|
// Sortable Lists
|
||||||
.sortable-page-list, .sortable-page-list ul {
|
.sortable-page-list, .sortable-page-list ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background-color: #FFF;
|
|
||||||
}
|
}
|
||||||
.sort-box {
|
.sort-box {
|
||||||
margin-bottom: $-m;
|
margin-bottom: $-m;
|
||||||
padding: 0 $-l 0 $-l;
|
border: 2px solid rgba($color-book, 0.6);
|
||||||
border-left: 4px solid $color-book;
|
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 {
|
.sortable-page-list {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
padding: 0;
|
||||||
|
.entity-list-item > span:first-child {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
.entity-list-item > div {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
> ul {
|
> ul {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
ul {
|
ul {
|
||||||
margin-bottom: 0;
|
margin-bottom: $-m;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.1);
|
padding-left: $-m;
|
||||||
}
|
}
|
||||||
li {
|
li {
|
||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
padding: $-xs $-s;
|
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
&.text-chapter {
|
&.text-chapter {
|
||||||
@ -228,18 +278,26 @@
|
|||||||
|
|
||||||
.activity-list-item {
|
.activity-list-item {
|
||||||
padding: $-s 0;
|
padding: $-s 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content 1fr;
|
||||||
|
grid-column-gap: $-m;
|
||||||
color: #888;
|
color: #888;
|
||||||
fill: #888;
|
fill: #888;
|
||||||
border-bottom: 1px solid #EEE;
|
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
.left {
|
}
|
||||||
float: left;
|
.card .activity-list-item {
|
||||||
}
|
padding: $-s $-m;
|
||||||
.left + .right {
|
}
|
||||||
margin-left: 30px + $-s;
|
|
||||||
}
|
.user-list-item {
|
||||||
&:last-of-type {
|
display: inline-grid;
|
||||||
border-bottom: 0;
|
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;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity-list {
|
.entity-list, .icon-list {
|
||||||
> div {
|
margin: 0 (-$-m);
|
||||||
padding: $-m 0;
|
|
||||||
}
|
|
||||||
h4 {
|
h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@ -302,15 +358,125 @@ ul.pagination {
|
|||||||
color: $color-page-draft;
|
color: $color-page-draft;
|
||||||
fill: $color-page-draft;
|
fill: $color-page-draft;
|
||||||
}
|
}
|
||||||
|
> .dropdown-container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card .entity-list-item, .card .activity-list-item {
|
.icon-list hr {
|
||||||
padding-left: $-m;
|
margin: $-s $-m;
|
||||||
padding-right: $-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 {
|
.entity-list.compact {
|
||||||
font-size: 0.6em;
|
font-size: 0.6 * $fs-m;
|
||||||
h4, a {
|
h4, a {
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
@ -331,6 +497,11 @@ ul.pagination {
|
|||||||
hr {
|
hr {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
@include smaller-than($m) {
|
||||||
|
h4 {
|
||||||
|
font-size: 1.666em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-container {
|
.dropdown-container {
|
||||||
@ -363,9 +534,8 @@ ul.pagination {
|
|||||||
color: #999;
|
color: #999;
|
||||||
fill: #999;
|
fill: #999;
|
||||||
}
|
}
|
||||||
li.padded {
|
li.active a {
|
||||||
padding: $-xs $-m;
|
font-weight: 600;
|
||||||
line-height: 1.2;
|
|
||||||
}
|
}
|
||||||
a, button {
|
a, button {
|
||||||
display: block;
|
display: block;
|
||||||
@ -396,7 +566,10 @@ ul.pagination {
|
|||||||
.featured-image-container {
|
.featured-image-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #F2F2F2;
|
min-height: 140px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
transition: opacity ease-in-out 240ms;
|
||||||
a {
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -405,11 +578,46 @@ ul.pagination {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
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) {
|
@mixin larger-than($size) {
|
||||||
@media screen and (min-width: $size) { @content; }
|
@media screen and (min-width: $size) { @content; }
|
||||||
}
|
}
|
||||||
@mixin clearfix() {
|
@mixin between($min, $max) {
|
||||||
&:after {
|
@media screen and (min-width: $min) and (max-width: $max) { @content; }
|
||||||
display: block;
|
|
||||||
content: '';
|
|
||||||
font-size: 0;
|
|
||||||
clear: both;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.faded-small {
|
background-color: #FFF;
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.edit-area {
|
.edit-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mce-tinymce {
|
.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 {
|
.draft-notification {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
@ -38,11 +71,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 840px;
|
max-width: 840px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
margin-top: $-xxl;
|
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
&.flex {
|
|
||||||
margin-top: $-m;
|
|
||||||
}
|
|
||||||
.align-left {
|
.align-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@ -248,13 +277,6 @@
|
|||||||
min-height: 0px;
|
min-height: 0px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
div[toolbox-tab-content] .padded {
|
|
||||||
flex: 1;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
div[toolbox-tab-content] .padded.files {
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
h4 {
|
h4 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
margin: $-m 0 0 0;
|
margin: $-m 0 0 0;
|
||||||
@ -349,16 +371,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-container {
|
.comments-container h5 {
|
||||||
width: 100%;
|
color: #888;
|
||||||
border-top: 1px solid #DDD;
|
font-weight: normal;
|
||||||
margin-top: $-xl;
|
margin-top: 0.5em;
|
||||||
margin-bottom: $-m;
|
|
||||||
h5 {
|
|
||||||
color: #888;
|
|
||||||
font-weight: normal;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
|
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
|
||||||
@ -370,4 +386,60 @@
|
|||||||
.mce-open {
|
.mce-open {
|
||||||
display: none;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
32
resources/assets/sass/_spacing.scss
Normal file
@ -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 {
|
table.table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
tr {
|
tr td, tr th {
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
th, td {
|
th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border: none;
|
border: none;
|
||||||
padding: $-xs $-xs;
|
padding: $-s $-s;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@ -44,6 +44,9 @@ table.table {
|
|||||||
td.actions {
|
td.actions {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table.no-style {
|
table.no-style {
|
||||||
|
@ -42,7 +42,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
color: #555;
|
color: #222;
|
||||||
.subheader {
|
.subheader {
|
||||||
font-size: 0.5em;
|
font-size: 0.5em;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
@ -79,10 +79,18 @@ h5, h6 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-heading {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2.list-heading {
|
||||||
|
font-size: 1.333rem;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Link styling
|
* Link styling
|
||||||
*/
|
*/
|
||||||
a, .link {
|
a {
|
||||||
color: $primary;
|
color: $primary;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@ -141,11 +149,8 @@ em, i, .italic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
small, p.small, span.small, .text-small {
|
small, p.small, span.small, .text-small {
|
||||||
font-size: 0.8em;
|
font-size: 0.75rem;
|
||||||
color: lighten($text-dark, 20%);
|
color: lighten($text-dark, 10%);
|
||||||
small, p.small, span.small, .text-small {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sup, .superscript {
|
sup, .superscript {
|
||||||
@ -233,106 +238,6 @@ pre code {
|
|||||||
display: block;
|
display: block;
|
||||||
line-height: 1.6;
|
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 {
|
span.highlight {
|
||||||
//background-color: rgba($primary, 0.2);
|
//background-color: rgba($primary, 0.2);
|
||||||
@ -435,10 +340,6 @@ span.sep {
|
|||||||
/**
|
/**
|
||||||
* Icons
|
* Icons
|
||||||
*/
|
*/
|
||||||
i {
|
|
||||||
padding-right: $-xs;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
@ -446,5 +347,6 @@ i {
|
|||||||
position: relative;
|
position: relative;
|
||||||
bottom: -0.105em;
|
bottom: -0.105em;
|
||||||
margin-right: $-xs;
|
margin-right: $-xs;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,13 @@
|
|||||||
text-align: center;
|
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 {
|
.edit-area.flex > div > .mce-tinymce.mce-container.mce-panel {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// Variables
|
// Variables
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
// Sizes
|
|
||||||
$max-width: 1400px;
|
|
||||||
|
|
||||||
// Screen breakpoints
|
// Screen breakpoints
|
||||||
|
$xxl: 1400px;
|
||||||
$xl: 1100px;
|
$xl: 1100px;
|
||||||
$ipad-width: 1028px; // Is actually 1024 but we go over to ensure functionality.
|
$ipad-width: 1028px; // Is actually 1024 but we go over to ensure functionality.
|
||||||
$l: 1000px;
|
$l: 1000px;
|
||||||
$m: 800px;
|
$m: 880px;
|
||||||
$s: 600px;
|
$s: 600px;
|
||||||
$xs: 400px;
|
$xs: 400px;
|
||||||
$xxs: 360px;
|
$xxs: 360px;
|
||||||
@ -16,6 +14,9 @@ $screen-lg: 1200px;
|
|||||||
$screen-md: 992px;
|
$screen-md: 992px;
|
||||||
$screen-sm: 768px;
|
$screen-sm: 768px;
|
||||||
|
|
||||||
|
// List of screen sizes
|
||||||
|
$screen-sizes: (('xxs', $xxs), ('xs', $xs), ('s', $s), ('m', $m), ('l', $l), ('xl', $xl));
|
||||||
|
|
||||||
// Spacing (Margins+Padding)
|
// Spacing (Margins+Padding)
|
||||||
$-xxxl: 64px;
|
$-xxxl: 64px;
|
||||||
$-xxl: 48px;
|
$-xxl: 48px;
|
||||||
@ -26,6 +27,9 @@ $-s: 12px;
|
|||||||
$-xs: 6px;
|
$-xs: 6px;
|
||||||
$-xxs: 3px;
|
$-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
|
// Fonts
|
||||||
$text: -apple-system, BlinkMacSystemFont,
|
$text: -apple-system, BlinkMacSystemFont,
|
||||||
"Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell",
|
"Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell",
|
||||||
@ -33,8 +37,8 @@ $text: -apple-system, BlinkMacSystemFont,
|
|||||||
sans-serif;
|
sans-serif;
|
||||||
$mono: "Lucida Console", "DejaVu Sans Mono", "Ubunto Mono", Monaco, monospace;
|
$mono: "Lucida Console", "DejaVu Sans Mono", "Ubunto Mono", Monaco, monospace;
|
||||||
$heading: $text;
|
$heading: $text;
|
||||||
$fs-m: 15px;
|
$fs-m: 14px;
|
||||||
$fs-s: 14px;
|
$fs-s: 12px;
|
||||||
|
|
||||||
// Colours
|
// Colours
|
||||||
$primary: #0288D1;
|
$primary: #0288D1;
|
||||||
@ -49,7 +53,7 @@ $primary-faded: rgba(21, 101, 192, 0.15);
|
|||||||
// Item Colors
|
// Item Colors
|
||||||
$color-bookshelf: #af5a5a;
|
$color-bookshelf: #af5a5a;
|
||||||
$color-book: #009688;
|
$color-book: #009688;
|
||||||
$color-chapter: #ef7c3c;
|
$color-chapter: #d7804a;
|
||||||
$color-page: $primary;
|
$color-page: $primary;
|
||||||
$color-page-draft: #9A60DA;
|
$color-page-draft: #9A60DA;
|
||||||
|
|
||||||
@ -60,5 +64,5 @@ $text-light: #EEE;
|
|||||||
// Shadows
|
// Shadows
|
||||||
$bs-light: 0 0 4px 1px #CCC;
|
$bs-light: 0 0 4px 1px #CCC;
|
||||||
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
|
$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);
|
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
|
@ -1,8 +1,9 @@
|
|||||||
@import "variables";
|
@import "variables";
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
|
@import "spacing";
|
||||||
@import "html";
|
@import "html";
|
||||||
@import "text";
|
@import "text";
|
||||||
@import "grid";
|
@import "layout";
|
||||||
@import "blocks";
|
@import "blocks";
|
||||||
@import "forms";
|
@import "forms";
|
||||||
@import "tables";
|
@import "tables";
|
||||||
@ -12,6 +13,9 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'DejaVu Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
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 {
|
table {
|
||||||
@ -19,6 +23,10 @@ table {
|
|||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent code block overflow on export
|
// Prevent code block overflow on export
|
||||||
pre {
|
pre {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
|
@ -8,10 +8,6 @@ body {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.faded-small {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-content {
|
.page-content {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
@import "reset";
|
@import "reset";
|
||||||
@import "variables";
|
@import "variables";
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
|
@import "spacing";
|
||||||
@import "html";
|
@import "html";
|
||||||
@import "text";
|
@import "text";
|
||||||
@import "grid";
|
@import "colors";
|
||||||
|
@import "layout";
|
||||||
@import "blocks";
|
@import "blocks";
|
||||||
@import "buttons";
|
@import "buttons";
|
||||||
@import "tables";
|
@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
|
// Back to top link
|
||||||
$btt-size: 40px;
|
$btt-size: 40px;
|
||||||
[back-to-top] {
|
[back-to-top] {
|
||||||
@ -186,22 +177,28 @@ $btt-size: 40px;
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
background-color: #EEEEEE;
|
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 {
|
.loading {
|
||||||
height: 400px;
|
height: 400px;
|
||||||
padding-top: $-l;
|
padding-top: $-l;
|
||||||
}
|
}
|
||||||
.entity-list > p {
|
.entity-selector-add button {
|
||||||
text-align: center;
|
margin: 0;
|
||||||
padding-top: $-l;
|
display: block;
|
||||||
font-size: 1.333em;
|
width: 100%;
|
||||||
}
|
border: 0;
|
||||||
.entity-list > div {
|
border-top: 1px solid #DDD;
|
||||||
padding-left: $-m;
|
|
||||||
padding-right: $-m;
|
|
||||||
background-color: #FFF;
|
|
||||||
transition: all ease-in-out 120ms;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
&.compact {
|
&.compact {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@ -211,12 +208,6 @@ $btt-size: 40px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity-list-item.selected {
|
|
||||||
h3, i, p ,a, span {
|
|
||||||
color: #EEE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-box {
|
.scroll-box {
|
||||||
max-height: 250px;
|
max-height: 250px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@ -254,3 +245,39 @@ $btt-size: 40px;
|
|||||||
height:100%;
|
height:100%;
|
||||||
z-index: 150;
|
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',
|
'save' => 'Save',
|
||||||
'continue' => 'Continue',
|
'continue' => 'Continue',
|
||||||
'select' => 'Select',
|
'select' => 'Select',
|
||||||
|
'toggle_all' => 'Toggle All',
|
||||||
'more' => 'More',
|
'more' => 'More',
|
||||||
|
|
||||||
// Form Labels
|
// Form Labels
|
||||||
@ -23,6 +24,7 @@ return [
|
|||||||
// Actions
|
// Actions
|
||||||
'actions' => 'Actions',
|
'actions' => 'Actions',
|
||||||
'view' => 'View',
|
'view' => 'View',
|
||||||
|
'view_all' => 'View All',
|
||||||
'create' => 'Create',
|
'create' => 'Create',
|
||||||
'update' => 'Update',
|
'update' => 'Update',
|
||||||
'edit' => 'Edit',
|
'edit' => 'Edit',
|
||||||
@ -37,6 +39,11 @@ return [
|
|||||||
'remove' => 'Remove',
|
'remove' => 'Remove',
|
||||||
'add' => 'Add',
|
'add' => 'Add',
|
||||||
|
|
||||||
|
// Sort Options
|
||||||
|
'sort_name' => 'Name',
|
||||||
|
'sort_created_at' => 'Created Date',
|
||||||
|
'sort_updated_at' => 'Updated Date',
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
'deleted_user' => 'Deleted User',
|
'deleted_user' => 'Deleted User',
|
||||||
'no_activity' => 'No activity to show',
|
'no_activity' => 'No activity to show',
|
||||||
@ -53,7 +60,11 @@ return [
|
|||||||
'view_profile' => 'View Profile',
|
'view_profile' => 'View Profile',
|
||||||
'edit_profile' => 'Edit Profile',
|
'edit_profile' => 'Edit Profile',
|
||||||
|
|
||||||
|
// Layout tabs
|
||||||
|
'tab_info' => 'Info',
|
||||||
|
'tab_content' => 'Content',
|
||||||
|
|
||||||
// Email 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_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',
|
'email_rights' => 'All rights reserved',
|
||||||
];
|
];
|
||||||
|
@ -11,6 +11,7 @@ return [
|
|||||||
'recently_updated_pages' => 'Recently Updated Pages',
|
'recently_updated_pages' => 'Recently Updated Pages',
|
||||||
'recently_created_chapters' => 'Recently Created Chapters',
|
'recently_created_chapters' => 'Recently Created Chapters',
|
||||||
'recently_created_books' => 'Recently Created Books',
|
'recently_created_books' => 'Recently Created Books',
|
||||||
|
'recently_created_shelves' => 'Recently Created Shelves',
|
||||||
'recently_update' => 'Recently Updated',
|
'recently_update' => 'Recently Updated',
|
||||||
'recently_viewed' => 'Recently Viewed',
|
'recently_viewed' => 'Recently Viewed',
|
||||||
'recent_activity' => 'Recent Activity',
|
'recent_activity' => 'Recent Activity',
|
||||||
@ -67,6 +68,7 @@ return [
|
|||||||
// Shelves
|
// Shelves
|
||||||
'shelf' => 'Shelf',
|
'shelf' => 'Shelf',
|
||||||
'shelves' => 'Shelves',
|
'shelves' => 'Shelves',
|
||||||
|
'x_shelves' => ':count Shelf|:count Shelves',
|
||||||
'shelves_long' => 'Bookshelves',
|
'shelves_long' => 'Bookshelves',
|
||||||
'shelves_empty' => 'No shelves have been created',
|
'shelves_empty' => 'No shelves have been created',
|
||||||
'shelves_create' => 'Create New Shelf',
|
'shelves_create' => 'Create New Shelf',
|
||||||
@ -117,7 +119,6 @@ return [
|
|||||||
'books_permissions_updated' => 'Book Permissions Updated',
|
'books_permissions_updated' => 'Book Permissions Updated',
|
||||||
'books_empty_contents' => 'No pages or chapters have been created for this book.',
|
'books_empty_contents' => 'No pages or chapters have been created for this book.',
|
||||||
'books_empty_create_page' => 'Create a new page',
|
'books_empty_create_page' => 'Create a new page',
|
||||||
'books_empty_or' => 'or',
|
|
||||||
'books_empty_sort_current_book' => 'Sort the current book',
|
'books_empty_sort_current_book' => 'Sort the current book',
|
||||||
'books_empty_add_chapter' => 'Add a chapter',
|
'books_empty_add_chapter' => 'Add a chapter',
|
||||||
'books_permissions_active' => 'Book Permissions Active',
|
'books_permissions_active' => 'Book Permissions Active',
|
||||||
@ -125,6 +126,11 @@ return [
|
|||||||
'books_navigation' => 'Book Navigation',
|
'books_navigation' => 'Book Navigation',
|
||||||
'books_sort' => 'Sort Book Contents',
|
'books_sort' => 'Sort Book Contents',
|
||||||
'books_sort_named' => 'Sort Book :bookName',
|
'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_show_other' => 'Show Other Books',
|
||||||
'books_sort_save' => 'Save New Order',
|
'books_sort_save' => 'Save New Order',
|
||||||
|
|
||||||
@ -202,6 +208,8 @@ return [
|
|||||||
'pages_revisions_created_by' => 'Created By',
|
'pages_revisions_created_by' => 'Created By',
|
||||||
'pages_revisions_date' => 'Revision Date',
|
'pages_revisions_date' => 'Revision Date',
|
||||||
'pages_revisions_number' => '#',
|
'pages_revisions_number' => '#',
|
||||||
|
'pages_revisions_numbered' => 'Revision #:id',
|
||||||
|
'pages_revisions_numbered_changes' => 'Revision #:id Changes',
|
||||||
'pages_revisions_changelog' => 'Changelog',
|
'pages_revisions_changelog' => 'Changelog',
|
||||||
'pages_revisions_changes' => 'Changes',
|
'pages_revisions_changes' => 'Changes',
|
||||||
'pages_revisions_current' => 'Current Version',
|
'pages_revisions_current' => 'Current Version',
|
||||||
@ -267,6 +275,7 @@ return [
|
|||||||
'profile_not_created_pages' => ':userName has not created any pages',
|
'profile_not_created_pages' => ':userName has not created any pages',
|
||||||
'profile_not_created_chapters' => ':userName has not created any chapters',
|
'profile_not_created_chapters' => ':userName has not created any chapters',
|
||||||
'profile_not_created_books' => ':userName has not created any books',
|
'profile_not_created_books' => ':userName has not created any books',
|
||||||
|
'profile_not_created_shelves' => ':userName has not created any shelves',
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
'comment' => 'Comment',
|
'comment' => 'Comment',
|
||||||
|
@ -12,34 +12,44 @@ return [
|
|||||||
'settings_save_success' => 'Settings saved',
|
'settings_save_success' => 'Settings saved',
|
||||||
|
|
||||||
// App Settings
|
// App Settings
|
||||||
'app_settings' => 'App Settings',
|
'app_customization' => 'Customization',
|
||||||
'app_name' => 'Application name',
|
'app_features_security' => 'Features & Security',
|
||||||
'app_name_desc' => 'This name is shown in the header and any emails.',
|
'app_name' => 'Application Name',
|
||||||
'app_name_header' => 'Show Application name in header?',
|
'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_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_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_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_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_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_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
|
||||||
'app_homepage' => 'Application Homepage',
|
'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_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_homepage_select' => 'Select a page',
|
||||||
'app_disable_comments' => 'Disable comments',
|
'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_toggle' => 'Disable comments',
|
||||||
|
'app_disable_comments_desc' => 'Disables comments across all pages in the application. <br> Existing comments are not shown.',
|
||||||
|
|
||||||
// Registration Settings
|
// Registration Settings
|
||||||
'reg_settings' => 'Registration Settings',
|
'reg_settings' => 'Registration',
|
||||||
'reg_allow' => 'Allow 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_default_role' => 'Default user role after registration',
|
||||||
'reg_confirm_email' => 'Require email confirmation?',
|
'reg_email_confirmation' => '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_email_confirmation_toggle' => 'Require email confirmation',
|
||||||
'reg_confirm_restrict_domain' => 'Restrict registration to domain',
|
'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_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',
|
'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
|
||||||
|
|
||||||
@ -91,9 +101,16 @@ return [
|
|||||||
'user_profile' => 'User Profile',
|
'user_profile' => 'User Profile',
|
||||||
'users_add_new' => 'Add New User',
|
'users_add_new' => 'Add New User',
|
||||||
'users_search' => 'Search Users',
|
'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' => '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_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_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' => 'Delete User',
|
||||||
'users_delete_named' => 'Delete user :userName',
|
'users_delete_named' => 'Delete user :userName',
|
||||||
@ -104,8 +121,9 @@ return [
|
|||||||
'users_edit_profile' => 'Edit Profile',
|
'users_edit_profile' => 'Edit Profile',
|
||||||
'users_edit_success' => 'User successfully updated',
|
'users_edit_success' => 'User successfully updated',
|
||||||
'users_avatar' => 'User Avatar',
|
'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' => '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' => '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_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',
|
'users_social_connect' => 'Connect Account',
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username">{{ trans('auth.username') }}</label>
|
<label for="username">{{ trans('auth.username') }}</label>
|
||||||
@include('form/text', ['name' => 'username', 'tabindex' => 1])
|
@include('form.text', ['name' => 'username', 'tabindex' => 1])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(session('request-email', false) === true)
|
@if(session('request-email', false) === true)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email">{{ trans('auth.email') }}</label>
|
<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">
|
<span class="text-neg">
|
||||||
{{ trans('auth.ldap_email_hint') }}
|
{{ trans('auth.ldap_email_hint') }}
|
||||||
</span>
|
</span>
|
||||||
@ -15,5 +15,5 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">{{ trans('auth.password') }}</label>
|
<label for="password">{{ trans('auth.password') }}</label>
|
||||||
@include('form/password', ['name' => 'password', 'tabindex' => 2])
|
@include('form.password', ['name' => 'password', 'tabindex' => 2])
|
||||||
</div>
|
</div>
|
@ -1,10 +1,10 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email">{{ trans('auth.email') }}</label>
|
<label for="email">{{ trans('auth.email') }}</label>
|
||||||
@include('form/text', ['name' => 'email', 'tabindex' => 1])
|
@include('form.text', ['name' => 'email', 'tabindex' => 1])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">{{ trans('auth.password') }}</label>
|
<label for="password">{{ trans('auth.password') }}</label>
|
||||||
@include('form/password', ['name' => 'password', 'tabindex' => 2])
|
@include('form.password', ['name' => 'password', 'tabindex' => 1])
|
||||||
<span class="block small"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
|
<span class="block small mt-s"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
|
||||||
</div>
|
</div>
|
@ -1,44 +1,48 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('header-buttons')
|
|
||||||
@if(setting('registration-enabled', false))
|
|
||||||
<a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
|
|
||||||
@endif
|
|
||||||
@stop
|
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="container very-small">
|
||||||
<div class="card center-box">
|
|
||||||
<h3>@icon('login') {{ title_case(trans('auth.log_in')) }}</h3>
|
|
||||||
|
|
||||||
<div class="body">
|
<div class="my-l"> </div>
|
||||||
<form action="{{ baseUrl("/login") }}" method="POST" id="login-form">
|
|
||||||
{!! csrf_field() !!}
|
|
||||||
|
|
||||||
@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">
|
<form action="{{ baseUrl("/login") }}" method="POST" id="login-form" class="mt-l">
|
||||||
<label for="remember" class="inline">{{ trans('auth.remember_me') }}</label>
|
{!! csrf_field() !!}
|
||||||
<input type="checkbox" id="remember" name="remember" class="toggle-switch-checkbox">
|
|
||||||
<label for="remember" class="toggle-switch"></label>
|
<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>
|
||||||
|
<div class="text-right">
|
||||||
<div class="from-group">
|
<button class="button primary" tabindex="3">{{ title_case(trans('auth.log_in')) }}</button>
|
||||||
<button class="button block pos" tabindex="3">@icon('login') {{ title_case(trans('auth.log_in')) }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
@if(count($socialDrivers) > 0)
|
</form>
|
||||||
<hr class="margin-top">
|
|
||||||
@foreach($socialDrivers as $driver => $name)
|
@if(count($socialDrivers) > 0)
|
||||||
<a id="social-login-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/login/service/" . $driver) }}">
|
<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)
|
@icon('auth/' . $driver)
|
||||||
{{ trans('auth.log_in_with', ['socialDriver' => $name]) }}
|
{{ trans('auth.log_in_with', ['socialDriver' => $name]) }}
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
</div>
|
||||||
@endif
|
@endforeach
|
||||||
</div>
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,37 +1,25 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
@section('content')
|
@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">
|
<form action="{{ baseUrl("/password/email") }}" method="POST" class="stretch-inputs">
|
||||||
<div class="card center-box">
|
{!! csrf_field() !!}
|
||||||
<h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
|
|
||||||
|
|
||||||
<div class="body">
|
<div class="form-group">
|
||||||
<p class="muted small">{{ trans('auth.reset_password_send_instructions') }}</p>
|
<label for="email">{{ trans('auth.email') }}</label>
|
||||||
|
@include('form.text', ['name' => 'email'])
|
||||||
|
</div>
|
||||||
|
|
||||||
<form action="{{ baseUrl("/password/email") }}" method="POST">
|
<div class="from-group text-right mt-m">
|
||||||
{!! csrf_field() !!}
|
<button class="button primary">{{ trans('auth.reset_password_send_button') }}</button>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
</form>
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@stop
|
@stop
|
@ -1,43 +1,34 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="container very-small mt-xl">
|
||||||
<div class="card center-box">
|
<div class="card content-wrap auto-height">
|
||||||
<h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
|
<h1 class="list-heading">{{ trans('auth.reset_password') }}</h1>
|
||||||
|
|
||||||
<div class="body">
|
<form action="{{ baseUrl("/password/reset") }}" method="POST" class="stretch-inputs">
|
||||||
<form action="{{ baseUrl("/password/reset") }}" method="POST">
|
{!! csrf_field() !!}
|
||||||
{!! csrf_field() !!}
|
<input type="hidden" name="token" value="{{ $token }}">
|
||||||
<input type="hidden" name="token" value="{{ $token }}">
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email">{{ trans('auth.email') }}</label>
|
<label for="email">{{ trans('auth.email') }}</label>
|
||||||
@include('form/text', ['name' => 'email'])
|
@include('form.text', ['name' => 'email'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">{{ trans('auth.password') }}</label>
|
<label for="password">{{ trans('auth.password') }}</label>
|
||||||
@include('form/password', ['name' => 'password'])
|
@include('form.password', ['name' => 'password'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
|
<label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
|
||||||
@include('form/password', ['name' => 'password_confirmation'])
|
@include('form.password', ['name' => 'password_confirmation'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="from-group text-right">
|
<div class="from-group text-right mt-m">
|
||||||
<button class="button primary">{{ trans('auth.reset_password') }}</button>
|
<button class="button primary">{{ trans('auth.reset_password') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('header-buttons')
|
|
||||||
@if(!$signedIn)
|
|
||||||
<a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
|
|
||||||
@endif
|
|
||||||
@stop
|
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="container very-small mt-xl">
|
||||||
<div class="card center-box">
|
<div class="card content-wrap auto-height">
|
||||||
<h3>@icon('users') {{ trans('auth.register_thanks') }}</h3>
|
<h1 class="list-heading">{{ trans('auth.register_thanks') }}</h1>
|
||||||
<div class="body">
|
<p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
|
||||||
<p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,50 +1,54 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('header-buttons')
|
|
||||||
<a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
|
|
||||||
@stop
|
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
<div class="container very-small">
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="my-l"> </div>
|
||||||
<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="form-group">
|
<div class="card content-wrap">
|
||||||
<label for="email">{{ trans('auth.name') }}</label>
|
<h1 class="list-heading">{{ title_case(trans('auth.sign_up')) }}</h1>
|
||||||
@include('form/text', ['name' => 'name'])
|
|
||||||
|
<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>
|
||||||
|
<div class="from-group text-right">
|
||||||
<div class="form-group">
|
<button class="button primary">{{ trans('auth.create_account') }}</button>
|
||||||
<label for="email">{{ trans('auth.email') }}</label>
|
|
||||||
@include('form/text', ['name' => 'email'])
|
|
||||||
</div>
|
</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">
|
</form>
|
||||||
<button class="button block pos">{{ trans('auth.create_account') }}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
@if(count($socialDrivers) > 0)
|
@if(count($socialDrivers) > 0)
|
||||||
<hr class="margin-top">
|
<hr class="my-l">
|
||||||
@foreach($socialDrivers as $driver => $name)
|
@foreach($socialDrivers as $driver => $name)
|
||||||
<a id="social-register-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/register/service/" . $driver) }}">
|
<div>
|
||||||
|
<a id="social-register-{{$driver}}" class="button block outline svg" href="{{ baseUrl("/register/service/" . $driver) }}">
|
||||||
@icon('auth/' . $driver)
|
@icon('auth/' . $driver)
|
||||||
{{ trans('auth.sign_up_with', ['socialDriver' => $name]) }}
|
{{ trans('auth.sign_up_with', ['socialDriver' => $name]) }}
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
</div>
|
||||||
@endif
|
@endforeach
|
||||||
</div>
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@stop
|
@stop
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
@extends('public')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<div class="container small">
|
<div class="container very-small mt-xl">
|
||||||
<p> </p>
|
<div class="card content-wrap auto-height">
|
||||||
<div class="card">
|
<h1 class="list-heading">{{ trans('auth.email_not_confirmed') }}</h1>
|
||||||
<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>
|
|
||||||
|
|
||||||
|
<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>
|
</div>
|
||||||
|
|
||||||
@stop
|
@stop
|
||||||
|
@ -17,75 +17,29 @@
|
|||||||
<script src="{{ baseUrl('/translations') }}"></script>
|
<script src="{{ baseUrl('/translations') }}"></script>
|
||||||
|
|
||||||
@yield('head')
|
@yield('head')
|
||||||
|
@include('partials.custom-styles')
|
||||||
@include('partials/custom-styles')
|
|
||||||
|
|
||||||
@include('partials.custom-head')
|
@include('partials.custom-head')
|
||||||
|
|
||||||
|
@stack('head')
|
||||||
</head>
|
</head>
|
||||||
<body class="@yield('body-class')" ng-app="bookStack">
|
<body class="@yield('body-class')">
|
||||||
|
|
||||||
@include('partials/notifications')
|
@include('partials.notifications')
|
||||||
|
@include('common.header')
|
||||||
<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>
|
|
||||||
|
|
||||||
<section id="content" class="block">
|
<section id="content" class="block">
|
||||||
@yield('content')
|
@yield('content')
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div back-to-top>
|
<div back-to-top class="primary-background">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
@icon('chevron-up') <span>{{ trans('common.back_to_top') }}</span>
|
@icon('chevron-up') <span>{{ trans('common.back_to_top') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@yield('bottom')
|
|
||||||
<script src="{{ versioned_asset('dist/app.js') }}"></script>
|
@yield('bottom')
|
||||||
@yield('scripts')
|
<script src="{{ versioned_asset('dist/app.js') }}"></script>
|
||||||
|
@yield('scripts')
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
@extends('simple-layout')
|
@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')
|
@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">
|
<div class="content-wrap card">
|
||||||
<p> </p>
|
<h1 class="list-heading">{{ trans('entities.books_create') }}</h1>
|
||||||
<div class="card">
|
|
||||||
<h3>@icon('add') {{ trans('entities.books_create') }}</h3>
|
|
||||||
<div class="body">
|
|
||||||
<form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
|
<form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
|
||||||
@include('books/form')
|
@include('books.form')
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<p class="margin-top large"><br></p>
|
|
||||||
@include('components.image-manager', ['imageType' => 'cover'])
|
@include('components.image-manager', ['imageType' => 'cover'])
|
||||||
@stop
|
@stop
|
@ -1,28 +1,30 @@
|
|||||||
@extends('simple-layout')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('toolbar')
|
|
||||||
<div class="col-sm-12 faded">
|
|
||||||
@include('books._breadcrumbs', ['book' => $book])
|
|
||||||
</div>
|
|
||||||
@stop
|
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
<div class="container small">
|
<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">
|
<div class="my-s">
|
||||||
{!! csrf_field() !!}
|
@include('partials.breadcrumbs', ['crumbs' => [
|
||||||
<input type="hidden" name="_method" value="DELETE">
|
$book,
|
||||||
<a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
|
$book->getUrl('/delete') => [
|
||||||
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
|
'text' => trans('entities.books_delete'),
|
||||||
</form>
|
'icon' => 'delete',
|
||||||
</div>
|
]
|
||||||
|
]])
|
||||||
|
</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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
@extends('simple-layout')
|
@extends('simple-layout')
|
||||||
|
|
||||||
@section('toolbar')
|
|
||||||
<div class="col-sm-12 faded">
|
|
||||||
@include('books._breadcrumbs', ['book' => $book])
|
|
||||||
</div>
|
|
||||||
@stop
|
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
<div class="container small">
|
<div class="container small">
|
||||||
<p> </p>
|
|
||||||
<div class="card">
|
<div class="my-s">
|
||||||
<h3>@icon('edit') {{ trans('entities.books_edit') }}</h3>
|
@include('partials.breadcrumbs', ['crumbs' => [
|
||||||
<div class="body">
|
$book,
|
||||||
<form action="{{ $book->getUrl() }}" method="POST">
|
$book->getUrl('/edit') => [
|
||||||
<input type="hidden" name="_method" value="PUT">
|
'text' => trans('entities.books_edit'),
|
||||||
@include('books/form', ['model' => $book])
|
'icon' => 'edit',
|
||||||
</form>
|
]
|
||||||
</div>
|
]])
|
||||||
|
</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>
|
||||||
</div>
|
</div>
|
||||||
@include('components.image-manager', ['imageType' => 'cover'])
|
|
||||||
|
@include('components.image-manager', ['imageType' => 'cover'])
|
||||||
@stop
|
@stop
|
@ -31,51 +31,51 @@
|
|||||||
@include('partials.custom-head')
|
@include('partials.custom-head')
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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)
|
<p>{{ $book->description }}</p>
|
||||||
<ul class="contents">
|
|
||||||
@foreach($bookChildren as $bookChild)
|
@if(count($bookChildren) > 0)
|
||||||
<li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
|
<ul class="contents">
|
||||||
@if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
|
@foreach($bookChildren as $bookChild)
|
||||||
<ul>
|
<li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
|
||||||
@foreach($bookChild->pages as $page)
|
@if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
|
||||||
<li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
|
<ul>
|
||||||
@endforeach
|
@foreach($bookChild->pages as $page)
|
||||||
</ul>
|
<li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
|
||||||
@endif
|
@endforeach
|
||||||
@endforeach
|
</ul>
|
||||||
</ul>
|
|
||||||
@endif
|
@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>
|
<div class="page-break"></div>
|
||||||
<h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
|
<div class="chapter-hint">{{$bookChild->name}}</div>
|
||||||
@if($bookChild->isA('chapter'))
|
<h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
|
||||||
<p>{{ $bookChild->description }}</p>
|
{!! $page->html !!}
|
||||||
@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
|
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@else
|
||||||
|
{!! $bookChild->html !!}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
{{ csrf_field() }}
|
{{ csrf_field() }}
|
||||||
<div class="form-group title-input">
|
<div class="form-group title-input">
|
||||||
<label for="name">{{ trans('common.name') }}</label>
|
<label for="name">{{ trans('common.name') }}</label>
|
||||||
@include('form/text', ['name' => 'name'])
|
@include('form.text', ['name' => 'name'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group description-input">
|
<div class="form-group description-input">
|
||||||
<label for="description">{{ trans('common.description') }}</label>
|
<label for="description">{{ trans('common.description') }}</label>
|
||||||
@include('form/textarea', ['name' => 'description'])
|
@include('form.textarea', ['name' => 'description'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" collapsible id="logo-control">
|
<div class="form-group" collapsible id="logo-control">
|
||||||
@ -41,5 +41,5 @@
|
|||||||
|
|
||||||
<div class="form-group text-right">
|
<div class="form-group text-right">
|
||||||
<a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
|
<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>
|
</div>
|
@ -1,18 +1,19 @@
|
|||||||
<div class="book-grid-item grid-card" data-entity-type="book" data-entity-id="{{$book->id}}">
|
<a href="{{$book->getUrl()}}" class="grid-card" data-entity-type="book" data-entity-id="{{$book->id}}">
|
||||||
<div class="featured-image-container">
|
<div class="bg-book featured-image-container-wrap">
|
||||||
<a href="{{$book->getUrl()}}" title="{{$book->name}}">
|
<div class="featured-image-container" @if($book->cover) style="background-image: url('{{ $book->getBookCover() }}')"@endif>
|
||||||
<img src="{{$book->getBookCover()}}" alt="{{$book->name}}">
|
</div>
|
||||||
</a>
|
@icon('book')
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-card-content">
|
<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))
|
@if(isset($book->searchSnippet))
|
||||||
<p >{!! $book->searchSnippet !!}</p>
|
<p class="text-muted">{!! $book->searchSnippet !!}</p>
|
||||||
@else
|
@else
|
||||||
<p >{{ $book->getExcerpt(130) }}</p>
|
<p class="text-muted">{{ $book->getExcerpt(130) }}</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-card-footer text-muted text-small">
|
<div class="grid-card-footer text-muted ">
|
||||||
<span>@include('partials.entity-meta', ['entity' => $book])</span>
|
<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>
|
||||||
</div>
|
</a>
|
@ -1,47 +1,52 @@
|
|||||||
@extends('sidebar-layout')
|
@extends('tri-layout')
|
||||||
|
|
||||||
@section('toolbar')
|
@section('container-classes', 'mt-xl')
|
||||||
<div class="col-xs-6">
|
|
||||||
<div class="action-buttons text-left">
|
@section('body')
|
||||||
@include('books/view-toggle', ['booksViewType' => $booksViewType])
|
@include('books.list', ['books' => $books, 'view' => $view])
|
||||||
</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>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('sidebar')
|
@section('left')
|
||||||
@if($recents)
|
@if($recents)
|
||||||
<div id="recents" class="card">
|
<div id="recents" class="mb-xl">
|
||||||
<h3>@icon('view') {{ trans('entities.recently_viewed') }}</h3>
|
<h5>{{ trans('entities.recently_viewed') }}</h5>
|
||||||
@include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
|
@include('partials.entity-list', ['entities' => $recents, 'style' => 'compact'])
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div id="popular" class="card">
|
<div id="popular" class="mb-xl">
|
||||||
<h3>@icon('popular') {{ trans('entities.books_popular') }}</h3>
|
<h5>{{ trans('entities.books_popular') }}</h5>
|
||||||
@if(count($popular) > 0)
|
@if(count($popular) > 0)
|
||||||
@include('partials/entity-list', ['entities' => $popular, 'style' => 'compact'])
|
@include('partials.entity-list', ['entities' => $popular, 'style' => 'compact'])
|
||||||
@else
|
@else
|
||||||
<div class="body text-muted">{{ trans('entities.books_popular_empty') }}</div>
|
<div class="body text-muted">{{ trans('entities.books_popular_empty') }}</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="new" class="card">
|
<div id="new" class="mb-xl">
|
||||||
<h3>@icon('star-circle') {{ trans('entities.books_new') }}</h3>
|
<h5>{{ trans('entities.books_new') }}</h5>
|
||||||
@if(count($popular) > 0)
|
@if(count($popular) > 0)
|
||||||
@include('partials/entity-list', ['entities' => $new, 'style' => 'compact'])
|
@include('partials.entity-list', ['entities' => $new, 'style' => 'compact'])
|
||||||
@else
|
@else
|
||||||
<div class="body text-muted">{{ trans('entities.books_new_empty') }}</div>
|
<div class="body text-muted">{{ trans('entities.books_new_empty') }}</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('body')
|
@section('right')
|
||||||
@include('books/list', ['books' => $books, 'bookViewType' => $booksViewType])
|
|
||||||
|
<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
|
@stop
|
@ -1,10 +1,11 @@
|
|||||||
<div class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
|
<a href="{{ $book->getUrl() }}" 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-list-item-image bg-book" style="background-image: url('{{ $book->getBookCover() }}')">
|
||||||
<div class="entity-item-snippet">
|
@icon('book')
|
||||||
@if(isset($book->searchSnippet))
|
|
||||||
<p class="text-muted break-text">{!! $book->searchSnippet !!}</p>
|
|
||||||
@else
|
|
||||||
<p class="text-muted break-text">{{ $book->getExcerpt() }}</p>
|
|
||||||
@endif
|
|
||||||
</div>
|
</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' : '' }}">
|
<div class="content-wrap mt-m card">
|
||||||
<h1>{{ trans('entities.books') }}</h1>
|
<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(count($books) > 0)
|
||||||
@if($booksViewType === 'list')
|
@if($view === 'list')
|
||||||
@foreach($books as $book)
|
<div class="entity-list">
|
||||||
@include('books/list-item', ['book' => $book])
|
@foreach($books as $book)
|
||||||
<hr>
|
@include('books.list-item', ['book' => $book])
|
||||||
@endforeach
|
@endforeach
|
||||||
{!! $books->render() !!}
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="grid third">
|
<div class="grid third">
|
||||||
@foreach($books as $key => $book)
|
@foreach($books as $key => $book)
|
||||||
@include('books/grid-item', ['book' => $book])
|
@include('books.grid-item', ['book' => $book])
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
{!! $books->render() !!}
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
<div>
|
||||||
|
{!! $books->render() !!}
|
||||||
|
</div>
|
||||||
@else
|
@else
|
||||||
<p class="text-muted">{{ trans('entities.books_empty') }}</p>
|
<p class="text-muted">{{ trans('entities.books_empty') }}</p>
|
||||||
@if(userCan('books-create-all'))
|
@if(userCan('books-create-all'))
|
||||||
|
23
resources/views/books/permissions.blade.php
Normal file
@ -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
|