* @param int $page
* @return array
*/
- public function entityActivity($entity, $count = 20, $page = 0)
+ public function entityActivity($entity, $count = 20, $page = 1)
{
if ($entity->isA('book')) {
$query = $this->activity->where('book_id', '=', $entity->id);
$activity = $this->permissionService
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
- ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get();
+ ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * ($page - 1))->take($count)->get();
return $this->filterSimilar($activity);
}
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Entities\Entity;
+use BookStack\Entities\EntityProvider;
+use Illuminate\Support\Collection;
class ViewService
{
protected $view;
protected $permissionService;
+ protected $entityProvider;
/**
* ViewService constructor.
* @param \BookStack\Actions\View $view
* @param \BookStack\Auth\Permissions\PermissionService $permissionService
+ * @param EntityProvider $entityProvider
*/
- public function __construct(View $view, PermissionService $permissionService)
+ public function __construct(View $view, PermissionService $permissionService, EntityProvider $entityProvider)
{
$this->view = $view;
$this->permissionService = $permissionService;
+ $this->entityProvider = $entityProvider;
}
/**
* Get the entities with the most views.
* @param int $count
* @param int $page
- * @param Entity|false|array $filterModel
+ * @param string|array $filterModels
* @param string $action - used for permission checking
- * @return
+ * @return Collection
*/
- public function getPopular($count = 10, $page = 0, $filterModel = false, $action = 'view')
+ public function getPopular(int $count = 10, int $page = 0, $filterModels = null, string $action = 'view')
{
- // TODO - Standardise input filter
$skipCount = $count * $page;
- $query = $this->permissionService->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action)
+ $query = $this->permissionService
+ ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action)
->select('*', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
->groupBy('viewable_id', 'viewable_type')
->orderBy('view_count', 'desc');
- if ($filterModel && is_array($filterModel)) {
- $query->whereIn('viewable_type', $filterModel);
- } else if ($filterModel) {
- $query->where('viewable_type', '=', $filterModel->getMorphClass());
+ if ($filterModels) {
+ $query->whereIn('viewable_type', $this->entityProvider->getMorphClasses($filterModels));
}
return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
$userCn = $this->getUserResponseProperty($user, 'cn', null);
return [
'uid' => $this->getUserResponseProperty($user, 'uid', $user['dn']),
- 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn),
+ 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn),
'dn' => $user['dn'],
'email' => $this->getUserResponseProperty($user, $emailAttr, null),
];
/**
* @param Authenticatable $user
- * @param string $username
- * @param string $password
+ * @param string $username
+ * @param string $password
* @return bool
* @throws LdapException
*/
throw new LdapException(trans('errors.ldap_extension_not_installed'));
}
- // Get port from server string and protocol if specified.
- $ldapServer = explode(':', $this->config['server']);
- $hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
- if (!$hasProtocol) {
- array_unshift($ldapServer, '');
- }
- $hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
- $defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
-
- /*
- * Check if TLS_INSECURE is set. The handle is set to NULL due to the nature of
- * the LDAP_OPT_X_TLS_REQUIRE_CERT option. It can only be set globally and not
- * per handle.
- */
+ // Check if TLS_INSECURE is set. The handle is set to NULL due to the nature of
+ // the LDAP_OPT_X_TLS_REQUIRE_CERT option. It can only be set globally and not per handle.
if ($this->config['tls_insecure']) {
$this->ldap->setOption(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
}
- $ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
+ $serverDetails = $this->parseServerString($this->config['server']);
+ $ldapConnection = $this->ldap->connect($serverDetails['host'], $serverDetails['port']);
if ($ldapConnection === false) {
throw new LdapException(trans('errors.ldap_cannot_connect'));
return $this->ldapConnection;
}
+ /**
+ * Parse a LDAP server string and return the host and port for
+ * a connection. Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com'
+ * @param $serverString
+ * @return array
+ */
+ protected function parseServerString($serverString)
+ {
+ $serverNameParts = explode(':', $serverString);
+
+ // If we have a protocol just return the full string since PHP will ignore a separate port.
+ if ($serverNameParts[0] === 'ldaps' || $serverNameParts[0] === 'ldap') {
+ return ['host' => $serverString, 'port' => 389];
+ }
+
+ // Otherwise, extract the port out
+ $hostName = $serverNameParts[0];
+ $ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
+ return ['host' => $hostName, 'port' => $ldapPort];
+ }
+
/**
* Build a filter string by injecting common variables.
* @param string $filterString
$count = 0;
if (isset($userGroupSearchResponse[$groupsAttr]['count'])) {
- $count = (int) $userGroupSearchResponse[$groupsAttr]['count'];
+ $count = (int)$userGroupSearchResponse[$groupsAttr]['count'];
}
- for ($i=0; $i<$count; $i++) {
+ for ($i = 0; $i < $count; $i++) {
$dnComponents = $this->ldap->explodeDn($userGroupSearchResponse[$groupsAttr][$i], 1);
if (!in_array($dnComponents[0], $ldapGroups)) {
$ldapGroups[] = $dnComponents[0];
$query2->where('has_permission_own', '=', 1)
->where('created_by', '=', $userId);
});
- }) ;
+ });
if (!is_null($entityClass)) {
$entityInstance = app()->make($entityClass);
* @param string $entityIdColumn
* @param string $entityTypeColumn
* @param string $action
- * @return mixed
+ * @return QueryBuilder
*/
public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn, $action = 'view')
{
<?php namespace BookStack\Auth;
use BookStack\Auth\Permissions\JointPermission;
+use BookStack\Auth\Permissions\RolePermission;
use BookStack\Model;
class Role extends Model
*/
public function users()
{
- return $this->belongsToMany(User::class);
+ return $this->belongsToMany(User::class)->orderBy('name', 'asc');
}
/**
*/
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');
}
/**
/**
* Add a permission to this role.
- * @param \BookStack\Auth\Permissions\RolePermission $permission
+ * @param RolePermission $permission
*/
- public function attachPermission(Permissions\RolePermission $permission)
+ public function attachPermission(RolePermission $permission)
{
$this->permissions()->attach($permission->id);
}
/**
* Detach a single permission from this role.
- * @param \BookStack\Auth\Permissions\RolePermission $permission
+ * @param RolePermission $permission
*/
- public function detachPermission(Permissions\RolePermission $permission)
+ public function detachPermission(RolePermission $permission)
{
$this->permissions()->detach($permission->id);
}
use BookStack\Exceptions\UserUpdateException;
use BookStack\Uploads\Image;
use Exception;
+use Illuminate\Database\Eloquent\Builder;
use Images;
class UserRepo
/**
* Get all the users with their permissions.
- * @return \Illuminate\Database\Eloquent\Builder|static
+ * @return Builder|static
*/
public function getAllUsers()
{
* Get all the users with their permissions in a paginated format.
* @param int $count
* @param $sortData
- * @return \Illuminate\Database\Eloquent\Builder|static
+ * @return Builder|static
*/
public function getAllUsersPaginatedAndSorted($count, $sortData)
{
*/
public function getRecentlyCreated(User $user, $count = 20)
{
+ $createdByUserQuery = function(Builder $query) use ($user) {
+ $query->where('created_by', '=', $user->id);
+ };
+
return [
- 'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) {
- $query->where('created_by', '=', $user->id);
- }),
- 'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) {
- $query->where('created_by', '=', $user->id);
- }),
- 'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) {
- $query->where('created_by', '=', $user->id);
- })
+ 'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, $createdByUserQuery),
+ 'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, $createdByUserQuery),
+ 'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, $createdByUserQuery),
+ 'shelves' => $this->entityRepo->getRecentlyCreated('bookshelf', $count, 0, $createdByUserQuery)
];
}
'pages' => $this->entityRepo->getUserTotalCreated('page', $user),
'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user),
'books' => $this->entityRepo->getUserTotalCreated('book', $user),
+ 'shelves' => $this->entityRepo->getUserTotalCreated('bookshelf', $user),
];
}
*/
public function getAllRoles()
{
- return $this->role->all();
+ return $this->role->newQuery()->orderBy('name', 'asc')->get();
}
/**
*/
public function getBookCover($width = 440, $height = 250)
{
- $default = baseUrl('/book_default_cover.png');
+ $default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
if (!$this->image_id) {
return $default;
}
return $this->hasMany(Page::class);
}
+ /**
+ * Get the direct child pages of this book.
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function directPages()
+ {
+ return $this->pages()->where('chapter_id', '=', '0');
+ }
+
/**
* Get all chapters within this book.
* @return \Illuminate\Database\Eloquent\Relations\HasMany
* @param int $length
* @return string
*/
- public function getExcerpt($length = 100)
+ public function getExcerpt(int $length = 100)
{
$description = $this->description;
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
*/
public function books()
{
- return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id')->orderBy('order', 'asc');
+ return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id')
+ ->withPivot('order')
+ ->orderBy('order', 'asc');
}
/**
*/
public function getBookCover($width = 440, $height = 250)
{
- $default = baseUrl('/book_default_cover.png');
+ // TODO - Make generic, focused on books right now, Perhaps set-up a better image
+ $default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
if (!$this->image_id) {
return $default;
}
}
/**
- * Get the cover image of the book
+ * Get the cover image of the shelf
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function cover()
* @param int $length
* @return string
*/
- public function getExcerpt($length = 100)
+ public function getExcerpt(int $length = 100)
{
$description = $this->description;
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
{
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;
+ }
}
--- /dev/null
+<?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);
+ }
+ }
+ }
+}
\ No newline at end of file
* @param int $length
* @return string
*/
- public function getExcerpt($length = 100)
+ public function getExcerpt(int $length = 100)
{
- $description = $this->description;
+ $description = $this->text ?? $this->description;
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
}
{
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;
+ }
}
return $this->morphMany(View::class, 'viewable');
}
+ public function viewCountQuery()
+ {
+ return $this->views()->selectRaw('viewable_id, sum(views) as view_count')->groupBy('viewable_id');
+ }
+
/**
* Get the Tag models that have been user assigned to this entity.
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
return $this->{$this->textField};
}
+ /**
+ * Get an excerpt of this entity's descriptive content to the specified length.
+ * @param int $length
+ * @return mixed
+ */
+ public function getExcerpt(int $length = 100)
+ {
+ $text = $this->getText();
+ if (mb_strlen($text) > $length) {
+ $text = mb_substr($text, 0, $length-3) . '...';
+ }
+ return trim($text);
+ }
+
/**
* Return a generalised, common raw query that can be 'unioned' across entities.
* @return string
--- /dev/null
+<?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);
+ }
+
+}
\ No newline at end of file
$type = strtolower($type);
return $this->all()[$type];
}
+
+ /**
+ * Get the morph classes, as an array, for a single or multiple types.
+ * @param string|array $types
+ * @return array<string>
+ */
+ public function getMorphClasses($types)
+ {
+ if (is_string($types)) {
+ $types = [$types];
+ }
+
+ $morphClasses = [];
+ foreach ($types as $type) {
+ $model = $this->get($type);
+ $morphClasses[] = $model->getMorphClass();
+ }
+ return $morphClasses;
+ }
}
return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent);
}
- /**
- * Get an excerpt of this page's content to the specified length.
- * @param int $length
- * @return mixed
- */
- public function getExcerpt($length = 100)
- {
- $text = strlen($this->text) > $length ? substr($this->text, 0, $length-3) . '...' : $this->text;
- return mb_convert_encoding($text, 'UTF-8');
- }
-
/**
* Return a generalised, common raw query that can be 'unioned' across entities.
* @param bool $withContent
{
return $type === 'revision';
}
+
}
use BookStack\Exceptions\NotifyException;
use BookStack\Uploads\AttachmentService;
use DOMDocument;
+use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
* Get all entities in a paginated format
* @param $type
* @param int $count
+ * @param string $sort
+ * @param string $order
+ * @param null|callable $queryAddition
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
- public function getAllPaginated($type, $count = 10)
+ public function getAllPaginated($type, int $count = 10, string $sort = 'name', string $order = 'asc', $queryAddition = null)
{
- return $this->entityQuery($type)->orderBy('name', 'asc')->paginate($count);
+ $query = $this->entityQuery($type);
+ $query = $this->addSortToQuery($query, $sort, $order);
+ if ($queryAddition) {
+ $queryAddition($query);
+ }
+ return $query->paginate($count);
+ }
+
+ /**
+ * Add sorting operations to an entity query.
+ * @param Builder $query
+ * @param string $sort
+ * @param string $order
+ * @return Builder
+ */
+ protected function addSortToQuery(Builder $query, string $sort = 'name', string $order = 'asc')
+ {
+ $order = ($order === 'asc') ? 'asc' : 'desc';
+ $propertySorts = ['name', 'created_at', 'updated_at'];
+
+ if (in_array($sort, $propertySorts)) {
+ return $query->orderBy($sort, $order);
+ }
+
+ return $query;
}
/**
/**
* Get the most popular entities base on all views.
- * @param string|bool $type
+ * @param string $type
* @param int $count
* @param int $page
* @return mixed
*/
- public function getPopular($type, $count = 10, $page = 0)
+ public function getPopular(string $type, int $count = 10, int $page = 0)
{
- $filter = is_bool($type) ? false : $this->entityProvider->get($type);
- return $this->viewService->getPopular($count, $page, $filter);
+ return $this->viewService->getPopular($count, $page, $type);
}
/**
return $this->permissionService->enforceEntityRestrictions('book', $bookshelf->books())->get();
}
+ /**
+ * Get the direct children of a book.
+ * @param Book $book
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ public function getBookDirectChildren(Book $book)
+ {
+ $pages = $this->permissionService->enforceEntityRestrictions('page', $book->directPages())->get();
+ $chapters = $this->permissionService->enforceEntityRestrictions('chapters', $book->chapters())->get();
+ return collect()->concat($pages)->concat($chapters)->sortBy('priority')->sortByDesc('draft');
+ }
+
/**
* Get all child objects of a book.
* Returns a sorted collection of Pages and Chapters.
$shelf->books()->sync($syncData);
}
+ /**
+ * Append a Book to a BookShelf.
+ * @param Bookshelf $shelf
+ * @param Book $book
+ */
+ public function appendBookToShelf(Bookshelf $shelf, Book $book)
+ {
+ if ($shelf->contains($book)) {
+ return;
+ }
+
+ $maxOrder = $shelf->books()->max('order');
+ $shelf->books()->attach($book->id, ['order' => $maxOrder + 1]);
+ }
+
/**
* Change the book that an entity belongs to.
* @param string $type
}
$doc = new DOMDocument();
+ libxml_use_internal_errors(true);
$doc->loadHTML(mb_convert_encoding('<body>'.$matchedPage->html.'</body>', 'HTML-ENTITIES', 'UTF-8'));
$matchingElem = $doc->getElementById($splitInclude[1]);
if ($matchingElem === null) {
$innerContent .= $doc->saveHTML($childNode);
}
}
+ libxml_clear_errors();
$html = str_replace($matches[0][$index], trim($innerContent), $html);
}
if ($htmlText == '') {
return $htmlText;
}
+
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
]);
}
- return view('auth/login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
+ return view('auth.login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
}
/**
*/
public function getRegisterConfirmation()
{
- return view('auth/register-confirm');
+ return view('auth.register-confirm');
}
/**
*/
public function showAwaitingConfirmation()
{
- return view('auth/user-unconfirmed');
+ return view('auth.user-unconfirmed');
}
/**
use Activity;
use BookStack\Auth\UserRepo;
use BookStack\Entities\Book;
+use BookStack\Entities\EntityContextManager;
use BookStack\Entities\Repos\EntityRepo;
use BookStack\Entities\ExportService;
use Illuminate\Http\Request;
protected $entityRepo;
protected $userRepo;
protected $exportService;
+ protected $entityContextManager;
/**
* BookController constructor.
* @param EntityRepo $entityRepo
- * @param \BookStack\Auth\UserRepo $userRepo
- * @param \BookStack\Entities\ExportService $exportService
+ * @param UserRepo $userRepo
+ * @param ExportService $exportService
+ * @param EntityContextManager $entityContextManager
*/
- public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
- {
+ public function __construct(
+ EntityRepo $entityRepo,
+ UserRepo $userRepo,
+ ExportService $exportService,
+ EntityContextManager $entityContextManager
+ ) {
$this->entityRepo = $entityRepo;
$this->userRepo = $userRepo;
$this->exportService = $exportService;
+ $this->entityContextManager = $entityContextManager;
parent::__construct();
}
*/
public function index()
{
- $books = $this->entityRepo->getAllPaginated('book', 18);
+ $view = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books'));
+ $sort = setting()->getUser($this->currentUser, 'books_sort', 'name');
+ $order = setting()->getUser($this->currentUser, 'books_sort_order', 'asc');
+ $sortOptions = [
+ 'name' => trans('common.sort_name'),
+ 'created_at' => trans('common.sort_created_at'),
+ 'updated_at' => trans('common.sort_updated_at'),
+ ];
+
+ $books = $this->entityRepo->getAllPaginated('book', 18, $sort, $order);
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
$popular = $this->entityRepo->getPopular('book', 4, 0);
$new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
- $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
+
+ $this->entityContextManager->clearShelfContext();
+
$this->setPageTitle(trans('entities.books'));
- return view('books/index', [
+ return view('books.index', [
'books' => $books,
'recents' => $recents,
'popular' => $popular,
'new' => $new,
- 'booksViewType' => $booksViewType
+ 'view' => $view,
+ 'sort' => $sort,
+ 'order' => $order,
+ 'sortOptions' => $sortOptions,
]);
}
/**
* Show the form for creating a new book.
+ * @param string $shelfSlug
* @return Response
+ * @throws \BookStack\Exceptions\NotFoundException
*/
- public function create()
+ public function create(string $shelfSlug = null)
{
+ $bookshelf = null;
+ if ($shelfSlug !== null) {
+ $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug);
+ $this->checkOwnablePermission('bookshelf-update', $bookshelf);
+ }
+
$this->checkPermission('book-create-all');
$this->setPageTitle(trans('entities.books_create'));
- return view('books/create');
+ return view('books.create', [
+ 'bookshelf' => $bookshelf
+ ]);
}
/**
* Store a newly created book in storage.
*
- * @param Request $request
+ * @param Request $request
+ * @param string $shelfSlug
* @return Response
+ * @throws \BookStack\Exceptions\NotFoundException
*/
- public function store(Request $request)
+ public function store(Request $request, string $shelfSlug = null)
{
$this->checkPermission('book-create-all');
$this->validate($request, [
'name' => 'required|string|max:255',
'description' => 'string|max:1000'
]);
+
+ $bookshelf = null;
+ if ($shelfSlug !== null) {
+ $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug);
+ $this->checkOwnablePermission('bookshelf-update', $bookshelf);
+ }
+
$book = $this->entityRepo->createFromInput('book', $request->all());
Activity::add($book, 'book_create', $book->id);
+
+ if ($bookshelf) {
+ $this->entityRepo->appendBookToShelf($bookshelf, $book);
+ Activity::add($bookshelf, 'bookshelf_update');
+ }
+
return redirect($book->getUrl());
}
/**
* Display the specified book.
* @param $slug
+ * @param Request $request
* @return Response
+ * @throws \BookStack\Exceptions\NotFoundException
*/
- public function show($slug)
+ public function show($slug, Request $request)
{
$book = $this->entityRepo->getBySlug('book', $slug);
$this->checkOwnablePermission('book-view', $book);
+
$bookChildren = $this->entityRepo->getBookChildren($book);
+
Views::add($book);
+ if ($request->has('shelf')) {
+ $this->entityContextManager->setShelfContext(intval($request->get('shelf')));
+ }
+
$this->setPageTitle($book->getShortName());
- return view('books/show', [
+ return view('books.show', [
'book' => $book,
'current' => $book,
'bookChildren' => $bookChildren,
- 'activity' => Activity::entityActivity($book, 20, 0)
+ 'activity' => Activity::entityActivity($book, 20, 1)
]);
}
$book = $this->entityRepo->getBySlug('book', $slug);
$this->checkOwnablePermission('book-update', $book);
$this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()]));
- return view('books/edit', ['book' => $book, 'current' => $book]);
+ return view('books.edit', ['book' => $book, 'current' => $book]);
}
/**
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('book-delete', $book);
$this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
- return view('books/delete', ['book' => $book, 'current' => $book]);
+ return view('books.delete', ['book' => $book, 'current' => $book]);
}
/**
* Shows the view which allows pages to be re-ordered and sorted.
* @param string $bookSlug
* @return \Illuminate\View\View
+ * @throws \BookStack\Exceptions\NotFoundException
*/
public function sort($bookSlug)
{
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('book-update', $book);
+
$bookChildren = $this->entityRepo->getBookChildren($book, true);
- $books = $this->entityRepo->getAll('book', false, 'update');
+
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
- return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
+ return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
}
/**
{
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$bookChildren = $this->entityRepo->getBookChildren($book);
- return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
+ return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
}
/**
* @param $bookSlug
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
- public function showRestrict($bookSlug)
+ public function showPermissions($bookSlug)
{
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $book);
$roles = $this->userRepo->getRestrictableRoles();
- return view('books/restrictions', [
+ return view('books.permissions', [
'book' => $book,
'roles' => $roles
]);
/**
* Set the restrictions for this book.
* @param $bookSlug
- * @param $bookSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+ * @throws \BookStack\Exceptions\NotFoundException
+ * @throws \Throwable
*/
- public function restrict($bookSlug, Request $request)
+ public function permissions($bookSlug, Request $request)
{
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $book);
use Activity;
use BookStack\Auth\UserRepo;
use BookStack\Entities\Bookshelf;
+use BookStack\Entities\EntityContextManager;
use BookStack\Entities\Repos\EntityRepo;
-use BookStack\Entities\ExportService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Views;
protected $entityRepo;
protected $userRepo;
- protected $exportService;
+ protected $entityContextManager;
/**
* BookController constructor.
- * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
+ * @param EntityRepo $entityRepo
* @param UserRepo $userRepo
- * @param \BookStack\Entities\ExportService $exportService
+ * @param EntityContextManager $entityContextManager
*/
- public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
+ public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, EntityContextManager $entityContextManager)
{
$this->entityRepo = $entityRepo;
$this->userRepo = $userRepo;
- $this->exportService = $exportService;
+ $this->entityContextManager = $entityContextManager;
parent::__construct();
}
*/
public function index()
{
- $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18);
+ $view = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
+ $sort = setting()->getUser($this->currentUser, 'bookshelves_sort', 'name');
+ $order = setting()->getUser($this->currentUser, 'bookshelves_sort_order', 'asc');
+ $sortOptions = [
+ 'name' => trans('common.sort_name'),
+ 'created_at' => trans('common.sort_created_at'),
+ 'updated_at' => trans('common.sort_updated_at'),
+ ];
+
+ $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $sort, $order);
+ foreach ($shelves as $shelf) {
+ $shelf->books = $this->entityRepo->getBookshelfChildren($shelf);
+ }
+
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false;
$popular = $this->entityRepo->getPopular('bookshelf', 4, 0);
$new = $this->entityRepo->getRecentlyCreated('bookshelf', 4, 0);
- $shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
+ $this->entityContextManager->clearShelfContext();
$this->setPageTitle(trans('entities.shelves'));
- return view('shelves/index', [
+ return view('shelves.index', [
'shelves' => $shelves,
'recents' => $recents,
'popular' => $popular,
'new' => $new,
- 'shelvesViewType' => $shelvesViewType
+ 'view' => $view,
+ 'sort' => $sort,
+ 'order' => $order,
+ 'sortOptions' => $sortOptions,
]);
}
$this->checkPermission('bookshelf-create-all');
$books = $this->entityRepo->getAll('book', false, 'update');
$this->setPageTitle(trans('entities.shelves_create'));
- return view('shelves/create', ['books' => $books]);
+ return view('shelves.create', ['books' => $books]);
}
/**
*/
public function show(string $slug)
{
- $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */
+ /** @var Bookshelf $bookshelf */
+ $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
$this->checkOwnablePermission('book-view', $bookshelf);
$books = $this->entityRepo->getBookshelfChildren($bookshelf);
Views::add($bookshelf);
+ $this->entityContextManager->setShelfContext($bookshelf->id);
$this->setPageTitle($bookshelf->getShortName());
- return view('shelves/show', [
+ return view('shelves.show', [
'shelf' => $bookshelf,
'books' => $books,
- 'activity' => Activity::entityActivity($bookshelf, 20, 0)
+ 'activity' => Activity::entityActivity($bookshelf, 20, 1)
]);
}
});
$this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $bookshelf->getShortName()]));
- return view('shelves/edit', [
+ return view('shelves.edit', [
'shelf' => $bookshelf,
'books' => $books,
'shelfBooks' => $shelfBooks,
$this->checkOwnablePermission('bookshelf-delete', $bookshelf);
$this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $bookshelf->getShortName()]));
- return view('shelves/delete', ['shelf' => $bookshelf]);
+ return view('shelves.delete', ['shelf' => $bookshelf]);
}
/**
}
/**
- * Show the Restrictions view.
- * @param $slug
+ * Show the permissions view.
+ * @param string $slug
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \BookStack\Exceptions\NotFoundException
*/
- public function showRestrict(string $slug)
+ public function showPermissions(string $slug)
{
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
$roles = $this->userRepo->getRestrictableRoles();
- return view('shelves.restrictions', [
+ return view('shelves.permissions', [
'shelf' => $bookshelf,
'roles' => $roles
]);
}
/**
- * Set the restrictions for this bookshelf.
- * @param $slug
+ * Set the permissions for this bookshelf.
+ * @param string $slug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \BookStack\Exceptions\NotFoundException
+ * @throws \Throwable
*/
- public function restrict(string $slug, Request $request)
+ public function permissions(string $slug, Request $request)
{
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug);
$this->checkOwnablePermission('restrictions-manage', $bookshelf);
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('chapter-create', $book);
$this->setPageTitle(trans('entities.chapters_create'));
- return view('chapters/create', ['book' => $book, 'current' => $book]);
+ return view('chapters.create', ['book' => $book, 'current' => $book]);
}
/**
Views::add($chapter);
$this->setPageTitle($chapter->getShortName());
$pages = $this->entityRepo->getChapterChildren($chapter);
- return view('chapters/show', [
+ return view('chapters.show', [
'book' => $chapter->book,
'chapter' => $chapter,
'current' => $chapter,
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
$this->checkOwnablePermission('chapter-update', $chapter);
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
- return view('chapters/edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
+ return view('chapters.edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
}
/**
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
$this->checkOwnablePermission('chapter-delete', $chapter);
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
- return view('chapters/delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
+ return view('chapters.delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
}
/**
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
$this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter);
- return view('chapters/move', [
+ return view('chapters.move', [
'chapter' => $chapter,
'book' => $chapter->book
]);
* @param $bookSlug
* @param $chapterSlug
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+ * @throws \BookStack\Exceptions\NotFoundException
*/
- public function showRestrict($bookSlug, $chapterSlug)
+ public function showPermissions($bookSlug, $chapterSlug)
{
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $chapter);
$roles = $this->userRepo->getRestrictableRoles();
- return view('chapters/restrictions', [
+ return view('chapters.permissions', [
'chapter' => $chapter,
'roles' => $roles
]);
* @param $chapterSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+ * @throws \BookStack\Exceptions\NotFoundException
+ * @throws \Throwable
*/
- public function restrict($bookSlug, $chapterSlug, Request $request)
+ public function permissions($bookSlug, $chapterSlug, Request $request)
{
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $chapter);
$this->checkPermission('comment-create-all');
$comment = $this->commentRepo->create($page, $request->only(['html', 'text', 'parent_id']));
Activity::add($page, 'commented_on', $page->book->id);
- return view('comments/comment', ['comment' => $comment]);
+ return view('comments.comment', ['comment' => $comment]);
}
/**
$this->checkOwnablePermission('comment-update', $comment);
$comment = $this->commentRepo->update($comment, $request->only(['html', 'text']));
- return view('comments/comment', ['comment' => $comment]);
+ return view('comments.comment', ['comment' => $comment]);
}
/**
return true;
}
+ /**
+ * Check if the current user has a permission or bypass if the provided user
+ * id matches the current user.
+ * @param string $permissionName
+ * @param int $userId
+ * @return bool
+ */
+ protected function checkPermissionOrCurrentUser(string $permissionName, int $userId)
+ {
+ return $this->checkPermissionOr($permissionName, function() use ($userId) {
+ return $userId === $this->currentUser->id;
+ });
+ }
+
/**
* Send back a json error message.
* @param string $messageText
parent::__construct();
}
-
/**
* Display the homepage.
* @return Response
'draftPages' => $draftPages,
];
+ // Add required list ordering & sorting for books & shelves views.
+ if ($homepageOption === 'bookshelves' || $homepageOption === 'books') {
+ $key = $homepageOption;
+ $view = setting()->getUser($this->currentUser, $key . '_view_type', config('app.views.' . $key));
+ $sort = setting()->getUser($this->currentUser, $key . '_sort', 'name');
+ $order = setting()->getUser($this->currentUser, $key . '_sort_order', 'asc');
+
+ $sortOptions = [
+ 'name' => trans('common.sort_name'),
+ 'created_at' => trans('common.sort_created_at'),
+ 'updated_at' => trans('common.sort_updated_at'),
+ ];
+
+ $commonData = array_merge($commonData, [
+ 'view' => $view,
+ 'sort' => $sort,
+ 'order' => $order,
+ 'sortOptions' => $sortOptions,
+ ]);
+ }
+
if ($homepageOption === 'bookshelves') {
- $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18);
- $shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid'));
- $data = array_merge($commonData, ['shelves' => $shelves, 'shelvesViewType' => $shelvesViewType]);
+ $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $commonData['sort'], $commonData['order']);
+ $data = array_merge($commonData, ['shelves' => $shelves]);
return view('common.home-shelves', $data);
}
if ($homepageOption === 'books') {
- $books = $this->entityRepo->getAllPaginated('book', 18);
- $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
- $data = array_merge($commonData, ['books' => $books, 'booksViewType' => $booksViewType]);
+ $books = $this->entityRepo->getAllPaginated('book', 18, $commonData['sort'], $commonData['order']);
+ $data = array_merge($commonData, ['books' => $books]);
return view('common.home-book', $data);
}
*/
public function customHeadContent()
{
- return view('partials/custom-head-content');
+ return view('partials.custom-head-content');
}
/**
$allowRobots = $sitePublic;
}
return response()
- ->view('common/robots', ['allowRobots' => $allowRobots])
+ ->view('common.robots', ['allowRobots' => $allowRobots])
->header('Content-Type', 'text/plain');
}
*/
public function getNotFound()
{
- return response()->view('errors/404', [], 404);
+ return response()->view('errors.404', [], 404);
}
}
{
$this->checkPermission('image-create-all');
$this->validate($request, [
- 'file' => 'image_extension|mimes:jpeg,png,gif,bmp,webp,tiff'
+ 'file' => 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'
]);
if (!$this->imageRepo->isValidType($type)) {
// Otherwise show the edit view if they're a guest
$this->setPageTitle(trans('entities.pages_new'));
- return view('pages/guest-create', ['parent' => $parent]);
+ return view('pages.guest-create', ['parent' => $parent]);
}
/**
$this->setPageTitle(trans('entities.pages_edit_draft'));
$draftsEnabled = $this->signedIn;
- return view('pages/edit', [
+ return view('pages.edit', [
'page' => $draft,
'book' => $draft->book,
'isDraft' => true,
Views::add($page);
$this->setPageTitle($page->getShortName());
- return view('pages/show', [
+ return view('pages.show', [
'page' => $page,'book' => $page->book,
'current' => $page,
'sidebarTree' => $sidebarTree,
}
$draftsEnabled = $this->signedIn;
- return view('pages/edit', [
+ return view('pages.edit', [
'page' => $page,
'book' => $page->book,
'current' => $page,
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('page-delete', $page);
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
- return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
+ return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
}
$page = $this->pageRepo->getById('page', $pageId, true);
$this->checkOwnablePermission('page-update', $page);
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
- return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
+ return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
}
/**
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\View\View
+ * @throws NotFoundException
*/
public function showRevisions($bookSlug, $pageSlug)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
- return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
+ return view('pages.revisions', ['page' => $page, 'current' => $page]);
}
/**
$page->fill($revision->toArray());
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
- return view('pages/revision', [
+ return view('pages.revision', [
'page' => $page,
'book' => $page->book,
+ 'diff' => null,
'revision' => $revision
]);
}
$page->fill($revision->toArray());
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
- return view('pages/revision', [
+ return view('pages.revision', [
'page' => $page,
'book' => $page->book,
'diff' => $diff,
// Check if its the latest revision, cannot delete latest revision.
if (intval($currentRevision->id) === intval($revId)) {
session()->flash('error', trans('entities.revision_cannot_delete_latest'));
- return response()->view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
+ return response()->view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
}
$revision->delete();
session()->flash('success', trans('entities.revision_delete_success'));
- return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
+ return view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
}
/**
return $this->downloadResponse($pageText, $pageSlug . '.txt');
}
- /**
- * Show a listing of recently created pages
- * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
- */
- public function showRecentlyCreated()
- {
- $pages = $this->pageRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
- return view('pages/detailed-listing', [
- 'title' => trans('entities.recently_created_pages'),
- 'pages' => $pages
- ]);
- }
-
/**
* Show a listing of recently created pages
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showRecentlyUpdated()
{
+ // TODO - Still exist?
$pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
- return view('pages/detailed-listing', [
+ return view('pages.detailed-listing', [
'title' => trans('entities.recently_updated_pages'),
'pages' => $pages
]);
}
- /**
- * Show the Restrictions view.
- * @param string $bookSlug
- * @param string $pageSlug
- * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
- */
- public function showRestrict($bookSlug, $pageSlug)
- {
- $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
- $this->checkOwnablePermission('restrictions-manage', $page);
- $roles = $this->userRepo->getRestrictableRoles();
- return view('pages/restrictions', [
- 'page' => $page,
- 'roles' => $roles
- ]);
- }
-
/**
* Show the view to choose a new parent to move a page into.
* @param string $bookSlug
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('page-update', $page);
$this->checkOwnablePermission('page-delete', $page);
- return view('pages/move', [
+ return view('pages.move', [
'book' => $page->book,
'page' => $page
]);
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('page-view', $page);
session()->flashInput(['name' => $page->name]);
- return view('pages/copy', [
+ return view('pages.copy', [
'book' => $page->book,
'page' => $page
]);
return redirect($pageCopy->getUrl());
}
+ /**
+ * Show the Permissions view.
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+ * @throws NotFoundException
+ */
+ public function showPermissions($bookSlug, $pageSlug)
+ {
+ $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
+ $this->checkOwnablePermission('restrictions-manage', $page);
+ $roles = $this->userRepo->getRestrictableRoles();
+ return view('pages.permissions', [
+ 'page' => $page,
+ 'roles' => $roles
+ ]);
+ }
+
/**
* Set the permissions for this page.
* @param string $bookSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws NotFoundException
+ * @throws \Throwable
*/
- public function restrict($bookSlug, $pageSlug, Request $request)
+ public function permissions($bookSlug, $pageSlug, Request $request)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $page);
{
$this->checkPermission('user-roles-manage');
$roles = $this->permissionsRepo->getAllRoles();
- return view('settings/roles/index', ['roles' => $roles]);
+ return view('settings.roles.index', ['roles' => $roles]);
}
/**
public function createRole()
{
$this->checkPermission('user-roles-manage');
- return view('settings/roles/create');
+ return view('settings.roles.create');
}
/**
if ($role->hidden) {
throw new PermissionsException(trans('errors.role_cannot_be_edited'));
}
- return view('settings/roles/edit', ['role' => $role]);
+ return view('settings.roles.edit', ['role' => $role]);
}
/**
$roles = $this->permissionsRepo->getAllRolesExcept($role);
$blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]);
$roles->prepend($blankRole);
- return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]);
+ return view('settings.roles.delete', ['role' => $role, 'roles' => $roles]);
}
/**
<?php namespace BookStack\Http\Controllers;
use BookStack\Actions\ViewService;
+use BookStack\Entities\EntityContextManager;
use BookStack\Entities\Repos\EntityRepo;
use BookStack\Entities\SearchService;
+use BookStack\Exceptions\NotFoundException;
+use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
+use Illuminate\View\View;
class SearchController extends Controller
{
protected $entityRepo;
protected $viewService;
protected $searchService;
+ protected $entityContextManager;
/**
* SearchController constructor.
- * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
+ * @param EntityRepo $entityRepo
* @param ViewService $viewService
* @param SearchService $searchService
+ * @param EntityContextManager $entityContextManager
*/
- public function __construct(EntityRepo $entityRepo, ViewService $viewService, SearchService $searchService)
- {
+ public function __construct(
+ EntityRepo $entityRepo,
+ ViewService $viewService,
+ SearchService $searchService,
+ EntityContextManager $entityContextManager
+ ) {
$this->entityRepo = $entityRepo;
$this->viewService = $viewService;
$this->searchService = $searchService;
+ $this->entityContextManager = $entityContextManager;
parent::__construct();
}
/**
* Searches all entities.
* @param Request $request
- * @return \Illuminate\View\View
+ * @return View
* @internal param string $searchTerm
*/
public function search(Request $request)
$results = $this->searchService->searchEntities($searchTerm, 'all', $page, 20);
- return view('search/all', [
+ return view('search.all', [
'entities' => $results['results'],
'totalResults' => $results['total'],
'searchTerm' => $searchTerm,
* Searches all entities within a book.
* @param Request $request
* @param integer $bookId
- * @return \Illuminate\View\View
+ * @return View
* @internal param string $searchTerm
*/
public function searchBook(Request $request, $bookId)
{
$term = $request->get('term', '');
$results = $this->searchService->searchBook($bookId, $term);
- return view('partials/entity-list', ['entities' => $results]);
+ return view('partials.entity-list', ['entities' => $results]);
}
/**
* Searches all entities within a chapter.
* @param Request $request
* @param integer $chapterId
- * @return \Illuminate\View\View
+ * @return View
* @internal param string $searchTerm
*/
public function searchChapter(Request $request, $chapterId)
{
$term = $request->get('term', '');
$results = $this->searchService->searchChapter($chapterId, $term);
- return view('partials/entity-list', ['entities' => $results]);
+ return view('partials.entity-list', ['entities' => $results]);
}
/**
*/
public function searchEntitiesAjax(Request $request)
{
- $entityTypes = $request->filled('types') ? collect(explode(',', $request->get('types'))) : collect(['page', 'chapter', 'book']);
+ $entityTypes = $request->filled('types') ? explode(',', $request->get('types')) : ['page', 'chapter', 'book'];
$searchTerm = $request->get('term', false);
$permission = $request->get('permission', 'view');
// Search for entities otherwise show most popular
if ($searchTerm !== false) {
- $searchTerm .= ' {type:'. implode('|', $entityTypes->toArray()) .'}';
+ $searchTerm .= ' {type:'. implode('|', $entityTypes) .'}';
$entities = $this->searchService->searchEntities($searchTerm, 'all', 1, 20, $permission)['results'];
} else {
- $entityNames = $entityTypes->map(function ($type) {
- return 'BookStack\\' . ucfirst($type); // TODO - Extract this elsewhere, too specific and stringy
- })->toArray();
- $entities = $this->viewService->getPopular(20, 0, $entityNames, $permission);
+ $entities = $this->viewService->getPopular(20, 0, $entityTypes, $permission);
+ }
+
+ return view('search.entity-ajax-list', ['entities' => $entities]);
+ }
+
+ /**
+ * 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('search/entity-ajax-list', ['entities' => $entities]);
+ return view('partials.entity-list-basic', ['entities' => $entities, 'style' => 'compact']);
}
}
<?php namespace BookStack\Http\Controllers;
+use BookStack\Auth\User;
use BookStack\Uploads\ImageService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
// Get application version
$version = trim(file_get_contents(base_path('version')));
- return view('settings/index', ['version' => $version]);
+ return view('settings.index', [
+ 'version' => $version,
+ 'guestUser' => User::getDefault()
+ ]);
}
/**
// Get application version
$version = trim(file_get_contents(base_path('version')));
- return view('settings/maintenance', ['version' => $version]);
+ return view('settings.maintenance', ['version' => $version]);
}
/**
$users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails);
$this->setPageTitle(trans('settings.users'));
$users->appends($listDetails);
- return view('users/index', ['users' => $users, 'listDetails' => $listDetails]);
+ return view('users.index', ['users' => $users, 'listDetails' => $listDetails]);
}
/**
$this->checkPermission('users-manage');
$authMethod = config('auth.method');
$roles = $this->userRepo->getAllRoles();
- return view('users/create', ['authMethod' => $authMethod, 'roles' => $roles]);
+ return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
}
/**
$activeSocialDrivers = $socialAuthService->getActiveDrivers();
$this->setPageTitle(trans('settings.user_profile'));
$roles = $this->userRepo->getAllRoles();
- return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
+ return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
}
/**
$user = $this->userRepo->getById($id);
$this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name]));
- return view('users/delete', ['user' => $user]);
+ return view('users.delete', ['user' => $user]);
}
/**
public function showProfilePage($id)
{
$user = $this->userRepo->getById($id);
+
$userActivity = $this->userRepo->getActivity($user);
$recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
$assetCounts = $this->userRepo->getAssetCounts($user);
- return view('users/profile', [
+
+ return view('users.profile', [
'user' => $user,
'activity' => $userActivity,
'recentlyCreated' => $recentlyCreated,
*/
public function switchBookView($id, Request $request)
{
- $this->checkPermissionOr('users-manage', function () use ($id) {
- return $this->currentUser->id == $id;
- });
+ return $this->switchViewType($id, $request, 'books');
+ }
+
+ /**
+ * Update the user's preferred shelf-list display setting.
+ * @param $id
+ * @param Request $request
+ * @return \Illuminate\Http\RedirectResponse
+ */
+ public function switchShelfView($id, Request $request)
+ {
+ return $this->switchViewType($id, $request, 'bookshelves');
+ }
+
+ /**
+ * For a type of list, switch with stored view type for a user.
+ * @param integer $userId
+ * @param Request $request
+ * @param string $listName
+ * @return \Illuminate\Http\RedirectResponse
+ */
+ protected function switchViewType($userId, Request $request, string $listName)
+ {
+ $this->checkPermissionOrCurrentUser('users-manage', $userId);
$viewType = $request->get('view_type');
if (!in_array($viewType, ['grid', 'list'])) {
$viewType = 'list';
}
- $user = $this->user->findOrFail($id);
- setting()->putUser($user, 'books_view_type', $viewType);
+ $user = $this->userRepo->getById($userId);
+ $key = $listName . '_view_type';
+ setting()->putUser($user, $key, $viewType);
- return redirect()->back(302, [], "/settings/users/$id");
+ return redirect()->back(302, [], "/settings/users/$userId");
}
/**
- * Update the user's preferred shelf-list display setting.
- * @param $id
+ * Change the stored sort type for a particular view.
+ * @param string $id
+ * @param string $type
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
- public function switchShelfView($id, Request $request)
+ public function changeSort(string $id, string $type, Request $request)
{
- $this->checkPermissionOr('users-manage', function () use ($id) {
- return $this->currentUser->id == $id;
- });
+ $validSortTypes = ['books', 'bookshelves'];
+ if (!in_array($type, $validSortTypes)) {
+ return redirect()->back(500);
+ }
+ return $this->changeListSort($id, $request, $type);
+ }
- $viewType = $request->get('view_type');
- if (!in_array($viewType, ['grid', 'list'])) {
- $viewType = 'list';
+ /**
+ * 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);
}
- $user = $this->userRepo->getById($id);
- setting()->putUser($user, 'bookshelves_view_type', $viewType);
+ $newState = $request->get('expand', 'false');
- return redirect()->back(302, [], "/settings/users/$id");
+ $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");
+ }
+
}
}
}
- if ($this->auth->guest() && !setting('app-public')) {
+ if (!hasAppAccess()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
use Blade;
use BookStack\Entities\Book;
use BookStack\Entities\Bookshelf;
+use BookStack\Entities\BreadcrumbsViewComposer;
use BookStack\Entities\Chapter;
use BookStack\Entities\Page;
use BookStack\Settings\Setting;
use BookStack\Settings\SettingService;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Schema;
use Validator;
return in_array(strtolower($value->getClientOriginalExtension()), $validImageExtensions);
});
+ Validator::extend('no_double_extension', function ($attribute, $value, $parameters, $validator) {
+ $uploadName = $value->getClientOriginalName();
+ return substr_count($uploadName, '.') < 2;
+ });
// Custom blade view directives
Blade::directive('icon', function ($expression) {
'BookStack\\Chapter' => Chapter::class,
'BookStack\\Page' => Page::class,
]);
+
+ // View Composers
+ View::composer('partials.breadcrumbs', BreadcrumbsViewComposer::class);
}
/**
namespace BookStack\Providers;
-use BookStack\Actions\Activity;
use BookStack\Actions\ActivityService;
-use BookStack\Actions\View;
use BookStack\Actions\ViewService;
-use BookStack\Auth\Permissions\PermissionService;
-use BookStack\Settings\Setting;
use BookStack\Settings\SettingService;
-use BookStack\Uploads\HttpFetcher;
-use BookStack\Uploads\Image;
use BookStack\Uploads\ImageService;
-use Illuminate\Contracts\Cache\Repository;
-use Illuminate\Contracts\Filesystem\Factory;
use Illuminate\Support\ServiceProvider;
-use Intervention\Image\ImageManager;
class CustomFacadeProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('activity', function () {
- return new ActivityService(
- $this->app->make(Activity::class),
- $this->app->make(PermissionService::class)
- );
+ return $this->app->make(ActivityService::class);
});
$this->app->bind('views', function () {
- return new ViewService(
- $this->app->make(View::class),
- $this->app->make(PermissionService::class)
- );
+ return $this->app->make(ViewService::class);
});
$this->app->bind('setting', function () {
- return new SettingService(
- $this->app->make(Setting::class),
- $this->app->make(Repository::class)
- );
+ return $this->app->make(SettingService::class);
});
$this->app->bind('images', function () {
- return new ImageService(
- $this->app->make(Image::class),
- $this->app->make(ImageManager::class),
- $this->app->make(Factory::class),
- $this->app->make(Repository::class),
- $this->app->make(HttpFetcher::class)
- );
+ return $this->app->make(ImageService::class);
});
}
}
*/
public function getUser($user, $key, $default = false)
{
+ if ($user->isDefault()) {
+ return session()->get($key, $default);
+ }
return $this->get($this->userKey($user->id, $key), $default);
}
+ /**
+ * Get a value for the current logged-in user.
+ * @param $key
+ * @param bool $default
+ * @return bool|string
+ */
+ public function getForCurrentUser($key, $default = false)
+ {
+ return $this->getUser(user(), $key, $default);
+ }
+
/**
* Gets a setting value from the cache or database.
* Looks at the system defaults if not cached or in database.
*/
public function putUser($user, $key, $value)
{
+ if ($user->isDefault()) {
+ return session()->put($key, $value);
+ }
return $this->put($this->userKey($user->id, $key), $value);
}
public function saveNewUpload(UploadedFile $uploadedFile, $page_id)
{
$attachmentName = $uploadedFile->getClientOriginalName();
- $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
+ $attachmentPath = $this->putFileInStorage($uploadedFile);
$largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
$attachment = Attachment::forceCreate([
}
$attachmentName = $uploadedFile->getClientOriginalName();
- $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
+ $attachmentPath = $this->putFileInStorage($uploadedFile);
$attachment->name = $attachmentName;
$attachment->path = $attachmentPath;
/**
* Store a file in storage with the given filename
- * @param $attachmentName
* @param UploadedFile $uploadedFile
* @return string
* @throws FileUploadException
*/
- protected function putFileInStorage($attachmentName, UploadedFile $uploadedFile)
+ protected function putFileInStorage(UploadedFile $uploadedFile)
{
$attachmentData = file_get_contents($uploadedFile->getRealPath());
$storage = $this->getStorage();
$basePath = 'uploads/files/' . Date('Y-m-M') . '/';
- $uploadFileName = $attachmentName;
+ $uploadFileName = str_random(16) . '.' . $uploadedFile->getClientOriginalExtension();
while ($storage->exists($basePath . $uploadFileName)) {
$uploadFileName = str_random(3) . $uploadFileName;
}
* Check if current user is a signed in user.
* @return bool
*/
-function signedInUser()
+function signedInUser() : bool
{
return auth()->user() && !auth()->user()->isDefault();
}
+/**
+ * Check if the current user has general access.
+ * @return bool
+ */
+function hasAppAccess() : bool {
+ return !auth()->guest() || setting('app-public');
+}
+
/**
* Check if the current user has a permission.
* If an ownable element is passed in the jointPermissions are checked against
'locale' => env('APP_LANG', 'en'),
// Locales available
- 'locales' => ['en', 'ar', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'kr', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW'],
+ 'locales' => ['en', 'ar', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'cs', 'sv', 'kr', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW'],
// Application Fallback Locale
'fallback_locale' => 'en',
"integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=",
"dev": true
},
- "alphanum-sort": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
- "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
- "dev": true
- },
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"dev": true
},
"autoprefixer": {
- "version": "8.6.5",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.6.5.tgz",
- "integrity": "sha512-PLWJN3Xo/rycNkx+mp8iBDMTm3FeWe4VmYaZDSqL5QQB9sLsQkG5k8n+LNDFnhh9kdq2K+egL/icpctOmDHwig==",
+ "version": "9.4.7",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.7.tgz",
+ "integrity": "sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA==",
"dev": true,
"requires": {
- "browserslist": "^3.2.8",
- "caniuse-lite": "^1.0.30000864",
+ "browserslist": "^4.4.1",
+ "caniuse-lite": "^1.0.30000932",
"normalize-range": "^0.1.2",
"num2fraction": "^1.2.2",
- "postcss": "^6.0.23",
- "postcss-value-parser": "^3.2.3"
+ "postcss": "^7.0.14",
+ "postcss-value-parser": "^3.3.1"
},
"dependencies": {
"browserslist": {
- "version": "3.2.8",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
- "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz",
+ "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30000929",
+ "electron-to-chromium": "^1.3.103",
+ "node-releases": "^1.1.3"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30000934",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000934.tgz",
+ "integrity": "sha512-o7yfZn0R9N+mWAuksDsdLsb1gu9o//XK0QSU0zSSReKNRsXsFc/n/psxi0YSPNiqlKxImp5h4DHnAPdwYJ8nNA==",
+ "dev": true
+ },
+ "electron-to-chromium": {
+ "version": "1.3.112",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.112.tgz",
+ "integrity": "sha512-FyVLdiRZnLw2WE5ECtveN0JJ7klyiz/HMfKE1/Rjff3l7pe4vfkYtBlcCqTckvR8E7asjJGh0m9gRPR3Anp/UA==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.7.tgz",
+ "integrity": "sha512-bKdrwaqJUPHqlCzDD7so/R+Nk0jGv9a11ZhLrD9f6i947qGLrGAhU3OxRENa19QQmwzGy/g6zCDEuLGDO8HPvA==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30000844",
- "electron-to-chromium": "^1.3.47"
+ "semver": "^5.3.0"
}
}
}
}
}
},
- "babel-code-frame": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
- "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "esutils": "^2.0.2",
- "js-tokens": "^3.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- }
- },
- "js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
"babel-loader": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz",
"dev": true
},
"cacache": {
- "version": "10.0.4",
- "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
- "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==",
- "dev": true,
- "requires": {
- "bluebird": "^3.5.1",
- "chownr": "^1.0.1",
- "glob": "^7.1.2",
- "graceful-fs": "^4.1.11",
- "lru-cache": "^4.1.1",
- "mississippi": "^2.0.0",
+ "version": "11.3.2",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
+ "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==",
+ "dev": true,
+ "requires": {
+ "bluebird": "^3.5.3",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.1.15",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.2",
- "ssri": "^5.2.4",
- "unique-filename": "^1.1.0",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
"y18n": "^4.0.0"
},
"dependencies": {
+ "bluebird": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
+ "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==",
+ "dev": true
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
+ "dev": true
}
}
},
"map-obj": "^1.0.0"
}
},
- "caniuse-api": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
- "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
- "dev": true,
- "requires": {
- "browserslist": "^1.3.6",
- "caniuse-db": "^1.0.30000529",
- "lodash.memoize": "^4.1.2",
- "lodash.uniq": "^4.5.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
- "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
- "dev": true,
- "requires": {
- "caniuse-db": "^1.0.30000639",
- "electron-to-chromium": "^1.2.7"
- }
- }
- }
- },
- "caniuse-db": {
- "version": "1.0.30000904",
- "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000904.tgz",
- "integrity": "sha512-iZ36AxtEx7ZiCBKhF2qFL8ED6u9zJGPU7Aq6HwZQYUbetBgYkGZfoPHq9z38jahV2kr8BgDYfXvftA35Ng2AaA==",
- "dev": true
- },
"caniuse-lite": {
"version": "1.0.30000904",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000904.tgz",
"safe-buffer": "^5.0.1"
}
},
- "clap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
- "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- }
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
"wrap-ansi": "^2.0.0"
}
},
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
"clone-deep": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true
},
- "coa": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
- "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
- "dev": true,
- "requires": {
- "q": "^1.1.2"
- }
- },
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"object-visit": "^1.0.0"
}
},
- "color": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
- "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
- "dev": true,
- "requires": {
- "clone": "^1.0.2",
- "color-convert": "^1.3.0",
- "color-string": "^0.3.0"
- }
- },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
- "color-string": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
- "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
- "dev": true,
- "requires": {
- "color-name": "^1.0.0"
- }
- },
- "colormin": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
- "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
- "dev": true,
- "requires": {
- "color": "^0.11.0",
- "css-color-names": "0.0.4",
- "has": "^1.0.1"
- }
- },
- "colors": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
- "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
- "dev": true
- },
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
}
},
"commander": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
- "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"dev": true
},
"commondir": {
"require-from-string": "^2.0.1"
},
"dependencies": {
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
- },
- "js-yaml": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
- "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"randomfill": "^1.0.3"
}
},
- "css-color-names": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
- "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
- "dev": true
- },
"css-loader": {
- "version": "0.28.11",
- "resolved": "http://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz",
- "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==",
- "dev": true,
- "requires": {
- "babel-code-frame": "^6.26.0",
- "css-selector-tokenizer": "^0.7.0",
- "cssnano": "^3.10.0",
- "icss-utils": "^2.1.0",
- "loader-utils": "^1.0.2",
- "lodash.camelcase": "^4.3.0",
- "object-assign": "^4.1.1",
- "postcss": "^5.0.6",
- "postcss-modules-extract-imports": "^1.2.0",
- "postcss-modules-local-by-default": "^1.2.0",
- "postcss-modules-scope": "^1.1.0",
- "postcss-modules-values": "^1.3.0",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.0.tgz",
+ "integrity": "sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^4.0.0",
+ "loader-utils": "^1.2.1",
+ "lodash": "^4.17.11",
+ "postcss": "^7.0.6",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^2.0.3",
+ "postcss-modules-scope": "^2.0.0",
+ "postcss-modules-values": "^2.0.0",
"postcss-value-parser": "^3.3.0",
- "source-list-map": "^2.0.0"
+ "schema-utils": "^1.0.0"
},
"dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "ajv": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
+ "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
"dev": true,
"requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
}
},
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
},
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
+ "minimist": "^1.2.0"
}
},
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "loader-utils": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
+ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^2.0.0",
+ "json5": "^1.0.1"
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
- "has-flag": "^1.0.0"
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
}
}
}
},
"regjsgen": {
"version": "0.2.0",
- "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
"integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
"dev": true
},
"integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
"dev": true
},
- "cssnano": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
- "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
"dev": true,
"requires": {
- "autoprefixer": "^6.3.1",
- "decamelize": "^1.1.2",
- "defined": "^1.0.0",
- "has": "^1.0.1",
- "object-assign": "^4.0.1",
- "postcss": "^5.0.14",
- "postcss-calc": "^5.2.0",
- "postcss-colormin": "^2.1.8",
- "postcss-convert-values": "^2.3.4",
- "postcss-discard-comments": "^2.0.4",
- "postcss-discard-duplicates": "^2.0.1",
- "postcss-discard-empty": "^2.0.1",
- "postcss-discard-overridden": "^0.1.1",
- "postcss-discard-unused": "^2.2.1",
- "postcss-filter-plugins": "^2.0.0",
- "postcss-merge-idents": "^2.1.5",
- "postcss-merge-longhand": "^2.0.1",
- "postcss-merge-rules": "^2.0.3",
- "postcss-minify-font-values": "^1.0.2",
- "postcss-minify-gradients": "^1.0.1",
- "postcss-minify-params": "^1.0.4",
- "postcss-minify-selectors": "^2.0.4",
- "postcss-normalize-charset": "^1.1.0",
- "postcss-normalize-url": "^3.0.7",
- "postcss-ordered-values": "^2.1.0",
- "postcss-reduce-idents": "^2.2.2",
- "postcss-reduce-initial": "^1.0.0",
- "postcss-reduce-transforms": "^1.0.3",
- "postcss-svgo": "^2.1.1",
- "postcss-unique-selectors": "^2.0.2",
- "postcss-value-parser": "^3.2.3",
- "postcss-zindex": "^2.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "autoprefixer": {
- "version": "6.7.7",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
- "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
- "dev": true,
- "requires": {
- "browserslist": "^1.7.6",
- "caniuse-db": "^1.0.30000634",
- "normalize-range": "^0.1.2",
- "num2fraction": "^1.2.2",
- "postcss": "^5.2.16",
- "postcss-value-parser": "^3.2.3"
- }
- },
- "browserslist": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
- "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
- "dev": true,
- "requires": {
- "caniuse-db": "^1.0.30000639",
- "electron-to-chromium": "^1.2.7"
- }
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "csso": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
- "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
- "dev": true,
- "requires": {
- "clap": "^1.0.9",
- "source-map": "^0.5.3"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- }
- }
- },
- "currently-unhandled": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
- "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
- "dev": true,
- "requires": {
- "array-find-index": "^1.0.1"
- }
- },
- "cyclist": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
- "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
- "dev": true
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "date-now": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
- "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
- "dev": true
- },
- "debug": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
- "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
+ "array-find-index": "^1.0.1"
+ }
+ },
+ "cyclist": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
+ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
+ "dev": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
+ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
},
"dependencies": {
"ms": {
}
}
},
- "defined": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
- "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
- "dev": true
- },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
}
},
"esprima": {
- "version": "2.7.3",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
- "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esrecurse": {
"is-extglob": "^1.0.0"
}
},
- "extract-text-webpack-plugin": {
- "version": "4.0.0-beta.0",
- "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-4.0.0-beta.0.tgz",
- "integrity": "sha512-Hypkn9jUTnFr0DpekNam53X47tXn3ucY08BQumv7kdGgeVUBLq3DJHJTi6HNxv4jl9W+Skxjz9+RnK0sJyqqjA==",
- "dev": true,
- "requires": {
- "async": "^2.4.1",
- "loader-utils": "^1.1.0",
- "schema-utils": "^0.4.5",
- "webpack-sources": "^1.1.0"
- },
- "dependencies": {
- "async": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
- "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
- "dev": true,
- "requires": {
- "lodash": "^4.14.0"
- }
- }
- }
- },
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"locate-path": "^2.0.0"
}
},
- "flatten": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
- "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
- "dev": true
- },
"flush-write-stream": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
"dev": true
},
- "html-comment-regex": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
- "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
- "dev": true
- },
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"dev": true
},
"icss-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz",
- "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.0.0.tgz",
+ "integrity": "sha512-bA/xGiwWM17qjllIs9X/y0EjsB7e0AV08F3OL8UPsoNkNRibIuu8f1eKTnQ8QO1DteKKTxTUAn+IEWUToIwGOA==",
"dev": true,
"requires": {
- "postcss": "^6.0.1"
+ "postcss": "^7.0.5"
}
},
"ieee754": {
"repeating": "^2.0.0"
}
},
- "indexes-of": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
- "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
- "dev": true
- },
"indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
"dev": true
},
- "is-absolute-url": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
- "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
- "dev": true
- },
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"kind-of": "^3.0.2"
}
},
- "is-plain-obj": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
- "dev": true
- },
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
- "is-svg": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
- "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
- "dev": true,
- "requires": {
- "html-comment-regex": "^1.1.0"
- }
- },
"is-symbol": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
"dev": true
},
"js-yaml": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
- "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "version": "3.12.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
+ "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
- "esprima": "^2.6.0"
+ "esprima": "^4.0.0"
}
},
"jsbn": {
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
"dev": true
},
- "lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
- "dev": true
- },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
- "lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
- "dev": true
- },
"lodash.mergewith": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",
"integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=",
"dev": true
},
- "lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
- "dev": true
- },
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz",
"integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA=="
},
- "math-expression-evaluator": {
- "version": "1.2.17",
- "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
- "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=",
- "dev": true
- },
"math-random": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
+ "mini-css-extract-plugin": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
+ "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "schema-utils": "^1.0.0",
+ "webpack-sources": "^1.1.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
+ "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
+ }
+ },
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"dev": true
},
"mississippi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz",
- "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
+ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
"dev": true,
"requires": {
"concat-stream": "^1.5.0",
"flush-write-stream": "^1.0.0",
"from2": "^2.1.0",
"parallel-transform": "^1.1.0",
- "pump": "^2.0.1",
+ "pump": "^3.0.0",
"pumpify": "^1.3.3",
"stream-each": "^1.1.0",
"through2": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
}
},
"mixin-deep": {
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
"dev": true
},
- "normalize-url": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
- "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
- "dev": true,
- "requires": {
- "object-assign": "^4.0.1",
- "prepend-http": "^1.0.0",
- "query-string": "^4.1.0",
- "sort-keys": "^1.0.0"
- }
- },
"npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"dev": true
},
"postcss": {
- "version": "6.0.23",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
- "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "version": "7.0.14",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
+ "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
"dev": true,
"requires": {
- "chalk": "^2.4.1",
+ "chalk": "^2.4.2",
"source-map": "^0.6.1",
- "supports-color": "^5.4.0"
- }
- },
- "postcss-calc": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
- "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.2",
- "postcss-message-helpers": "^2.0.0",
- "reduce-css-calc": "^1.2.6"
+ "supports-color": "^6.1.0"
},
"dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
"chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
}
}
},
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-colormin": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
- "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
- "dev": true,
- "requires": {
- "colormin": "^1.0.5",
- "postcss": "^5.0.13",
- "postcss-value-parser": "^3.2.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-convert-values": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
- "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.11",
- "postcss-value-parser": "^3.1.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-discard-comments": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
- "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.14"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-discard-duplicates": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
- "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-discard-empty": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
- "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.14"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-discard-overridden": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
- "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.16"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-discard-unused": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
- "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.14",
- "uniqs": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-filter-plugins": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
- "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-load-config": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz",
- "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==",
- "dev": true,
- "requires": {
- "cosmiconfig": "^4.0.0",
- "import-cwd": "^2.0.0"
- }
- },
- "postcss-loader": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.6.tgz",
- "integrity": "sha512-hgiWSc13xVQAq25cVw80CH0l49ZKlAnU1hKPOdRrNj89bokRr/bZF2nT+hebPPF9c9xs8c3gw3Fr2nxtmXYnNg==",
- "dev": true,
- "requires": {
- "loader-utils": "^1.1.0",
- "postcss": "^6.0.0",
- "postcss-load-config": "^2.0.0",
- "schema-utils": "^0.4.0"
- }
- },
- "postcss-merge-idents": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
- "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
- "dev": true,
- "requires": {
- "has": "^1.0.1",
- "postcss": "^5.0.10",
- "postcss-value-parser": "^3.1.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-merge-longhand": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
- "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-merge-rules": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
- "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
- "dev": true,
- "requires": {
- "browserslist": "^1.5.2",
- "caniuse-api": "^1.5.2",
- "postcss": "^5.0.4",
- "postcss-selector-parser": "^2.2.2",
- "vendors": "^1.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "browserslist": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
- "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
- "dev": true,
- "requires": {
- "caniuse-db": "^1.0.30000639",
- "electron-to-chromium": "^1.2.7"
- }
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-message-helpers": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
- "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
- "dev": true
- },
- "postcss-minify-font-values": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
- "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
- "dev": true,
- "requires": {
- "object-assign": "^4.0.1",
- "postcss": "^5.0.4",
- "postcss-value-parser": "^3.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-minify-gradients": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
- "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.12",
- "postcss-value-parser": "^3.3.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-minify-params": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
- "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
- "dev": true,
- "requires": {
- "alphanum-sort": "^1.0.1",
- "postcss": "^5.0.2",
- "postcss-value-parser": "^3.0.2",
- "uniqs": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-minify-selectors": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
- "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
- "dev": true,
- "requires": {
- "alphanum-sort": "^1.0.2",
- "has": "^1.0.1",
- "postcss": "^5.0.14",
- "postcss-selector-parser": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-modules-extract-imports": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz",
- "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==",
- "dev": true,
- "requires": {
- "postcss": "^6.0.1"
- }
- },
- "postcss-modules-local-by-default": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
- "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
- "dev": true,
- "requires": {
- "css-selector-tokenizer": "^0.7.0",
- "postcss": "^6.0.1"
- }
- },
- "postcss-modules-scope": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
- "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
- "dev": true,
- "requires": {
- "css-selector-tokenizer": "^0.7.0",
- "postcss": "^6.0.1"
- }
- },
- "postcss-modules-values": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
- "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
- "dev": true,
- "requires": {
- "icss-replace-symbols": "^1.1.0",
- "postcss": "^6.0.1"
- }
- },
- "postcss-normalize-charset": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
- "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.5"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-normalize-url": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
- "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
- "dev": true,
- "requires": {
- "is-absolute-url": "^2.0.0",
- "normalize-url": "^1.4.0",
- "postcss": "^5.0.14",
- "postcss-value-parser": "^3.2.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-ordered-values": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
- "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4",
- "postcss-value-parser": "^3.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-reduce-idents": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
- "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4",
- "postcss-value-parser": "^3.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-reduce-initial": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
- "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
- "dev": true,
- "requires": {
- "postcss": "^5.0.4"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-reduce-transforms": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
- "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
- "dev": true,
- "requires": {
- "has": "^1.0.1",
- "postcss": "^5.0.8",
- "postcss-value-parser": "^3.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
- }
- },
- "postcss-selector-parser": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
- "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
- "dev": true,
- "requires": {
- "flatten": "^1.0.2",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- },
- "postcss-svgo": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
- "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
- "dev": true,
- "requires": {
- "is-svg": "^2.0.0",
- "postcss": "^5.0.14",
- "postcss-value-parser": "^3.2.3",
- "svgo": "^0.7.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
+ "has-flag": "^3.0.0"
}
}
}
},
- "postcss-unique-selectors": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
- "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+ "postcss-load-config": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz",
+ "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==",
"dev": true,
"requires": {
- "alphanum-sort": "^1.0.1",
- "postcss": "^5.0.4",
- "uniqs": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "^1.0.0"
- }
- }
+ "cosmiconfig": "^4.0.0",
+ "import-cwd": "^2.0.0"
}
},
- "postcss-value-parser": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
- "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
- "dev": true
- },
- "postcss-zindex": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
- "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
- "dev": true,
- "requires": {
- "has": "^1.0.1",
- "postcss": "^5.0.4",
- "uniqs": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "postcss-loader": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
+ "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "postcss": "^7.0.0",
+ "postcss-load-config": "^2.0.0",
+ "schema-utils": "^1.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
+ "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
"dev": true,
"requires": {
- "chalk": "^1.1.3",
- "js-base64": "^2.1.9",
- "source-map": "^0.5.6",
- "supports-color": "^3.2.3"
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
}
},
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
- "has-flag": "^1.0.0"
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
}
}
}
},
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+ "postcss-modules-extract-imports": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
+ "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.5"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.4.tgz",
+ "integrity": "sha512-WvuSaTKXUqYJbnT7R3YrsNrHv/C5vRfr5VglS4bFOk0MYT4CLBfc/xgExA+x2RftlYgiBDvWmVs191Xv8S8gZQ==",
+ "dev": true,
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^7.0.6",
+ "postcss-value-parser": "^3.3.1"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.0.1.tgz",
+ "integrity": "sha512-7+6k9c3/AuZ5c596LJx9n923A/j3nF3ormewYBF1RrIQvjvjXe1xE8V8A1KFyFwXbvnshT6FBZFX0k/F1igneg==",
+ "dev": true,
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^7.0.6"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz",
+ "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==",
+ "dev": true,
+ "requires": {
+ "icss-replace-symbols": "^1.1.0",
+ "postcss": "^7.0.6"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
},
"preserve": {
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
},
- "q": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
- "dev": true
- },
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
},
- "query-string": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
- "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
- "dev": true,
- "requires": {
- "object-assign": "^4.1.0",
- "strict-uri-encode": "^1.0.0"
- }
- },
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"strip-indent": "^1.0.1"
}
},
- "reduce-css-calc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
- "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
- "dev": true,
- "requires": {
- "balanced-match": "^0.4.2",
- "math-expression-evaluator": "^1.2.14",
- "reduce-function-call": "^1.0.1"
- },
- "dependencies": {
- "balanced-match": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
- "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
- "dev": true
- }
- }
- },
- "reduce-function-call": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
- "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
- "dev": true,
- "requires": {
- "balanced-match": "^0.4.2"
- },
- "dependencies": {
- "balanced-match": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
- "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
- "dev": true
- }
- }
- },
"regenerate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
"semver": "^5.5.0"
}
},
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "dev": true
- },
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
"kind-of": "^3.2.0"
}
},
- "sort-keys": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
- "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
- "dev": true,
- "requires": {
- "is-plain-obj": "^1.0.0"
- }
- },
"sortablejs": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.7.0.tgz",
}
},
"ssri": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz",
- "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
"dev": true,
"requires": {
- "safe-buffer": "^5.1.1"
+ "figgy-pudding": "^3.5.1"
}
},
"static-extend": {
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
"dev": true
},
- "strict-uri-encode": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
- "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
- "dev": true
- },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
}
},
"style-loader": {
- "version": "0.21.0",
- "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.21.0.tgz",
- "integrity": "sha512-T+UNsAcl3Yg+BsPKs1vd22Fr8sVT+CJMtzqc6LEw9bbJZb43lm9GoeIfUcDEefBSWC0BhYbcdupV1GtI4DGzxg==",
+ "version": "0.23.1",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
+ "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==",
"dev": true,
"requires": {
"loader-utils": "^1.1.0",
- "schema-utils": "^0.4.5"
+ "schema-utils": "^1.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
+ "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
}
},
"supports-color": {
"has-flag": "^3.0.0"
}
},
- "svgo": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
- "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
- "dev": true,
- "requires": {
- "coa": "~1.0.1",
- "colors": "~1.1.2",
- "csso": "~2.3.1",
- "js-yaml": "~3.7.0",
- "mkdirp": "~0.5.1",
- "sax": "~1.2.1",
- "whet.extend": "~0.9.9"
- }
- },
"tapable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
"integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg=="
},
- "uglify-es": {
- "version": "3.3.9",
- "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
- "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
+ "uglify-js": {
+ "version": "3.4.9",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
+ "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"dev": true,
"requires": {
- "commander": "~2.13.0",
+ "commander": "~2.17.1",
"source-map": "~0.6.1"
}
},
"uglifyjs-webpack-plugin": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
- "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-2.1.1.tgz",
+ "integrity": "sha512-TQEcyMNkObX/H+FfcKjiDgs5RcXX8vW2UUUrDTOfQgg3lrafztfeM5WAwXo+AzqozJK6NP9w98xNpG/dutzSsg==",
"dev": true,
"requires": {
- "cacache": "^10.0.4",
- "find-cache-dir": "^1.0.0",
- "schema-utils": "^0.4.5",
+ "cacache": "^11.2.0",
+ "find-cache-dir": "^2.0.0",
+ "schema-utils": "^1.0.0",
"serialize-javascript": "^1.4.0",
"source-map": "^0.6.1",
- "uglify-es": "^3.3.4",
+ "uglify-js": "^3.0.0",
"webpack-sources": "^1.1.0",
"worker-farm": "^1.5.2"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
+ "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "find-cache-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz",
+ "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^1.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
+ "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
+ "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
}
},
"ultron": {
}
}
},
- "uniq": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
- "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
- "dev": true
- },
- "uniqs": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
- "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
- "dev": true
- },
"unique-filename": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
"spdx-expression-parse": "^3.0.0"
}
},
- "vendors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz",
- "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==",
- "dev": true
- },
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"source-map": "~0.6.1"
}
},
- "whet.extend": {
- "version": "0.9.9",
- "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
- "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
- "dev": true
- },
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"@babel/core": "^7.1.6",
"@babel/polyfill": "^7.0.0",
"@babel/preset-env": "^7.1.6",
- "autoprefixer": "^8.6.5",
+ "autoprefixer": "^9.4.7",
"babel-loader": "^8.0.4",
- "css-loader": "^0.28.11",
- "extract-text-webpack-plugin": "^4.0.0-beta.0",
+ "css-loader": "^2.1.0",
"livereload": "^0.7.0",
+ "mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.10.0",
"npm-run-all": "^4.1.5",
- "postcss-loader": "^2.1.6",
+ "postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
- "style-loader": "^0.21.0",
- "uglifyjs-webpack-plugin": "^1.3.0",
+ "style-loader": "^0.23.1",
+ "uglifyjs-webpack-plugin": "^2.1.1",
"webpack": "^4.26.1",
"webpack-cli": "^3.1.2"
},
The website which contains the project docs & Blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo.
+## Security
+
+Security information for administering a BookStack instance can be found on the [documentation site here](https://www.bookstackapp.com/docs/admin/security/).
+
+If you'd like to be notified of new potential security concerns you can [sign-up to the BookStack security mailing list](http://eepurl.com/glIh8z).
+
+If you would like to report a security concern in a more confidential manner than via a GitHub issue, You can directly email the lead maintainer [ssddanbrown](https://github.com/ssddanbrown). You will need to login to be able to see the email address on the [GitHub profile page](https://github.com/ssddanbrown). Alternatively you can send a DM via twitter to [@ssddanbrown](https://twitter.com/ssddanbrown).
+
+
## License
The BookStack source is provided under the MIT License.
-<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
- <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
- <path d="M0 0h24v24H0z" fill="none"/>
-</svg>
\ No newline at end of file
+<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>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19.252 1.708H8.663a1.77 1.77 0 0 0-1.765 1.764v14.12c0 .97.794 1.764 1.765 1.764h10.59a1.77 1.77 0 0 0 1.764-1.765V3.472a1.77 1.77 0 0 0-1.765-1.764zM8.663 3.472h4.412v7.06L10.87 9.208l-2.206 1.324z"/><path d="M30.61 3.203h24v24h-24z" fill="none"/><path d="M2.966 6.61v14c0 1.1.9 2 2 2h14v-2h-14v-14z"/></svg>
\ No newline at end of file
-<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>
\ No newline at end of file
--- /dev/null
+<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>
\ No newline at end of file
--- /dev/null
+<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>
\ No newline at end of file
--- /dev/null
+<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>
\ No newline at end of file
--- /dev/null
+<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>
\ No newline at end of file
--- /dev/null
+
+
+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;
\ No newline at end of file
constructor(elem) {
this.container = elem;
- this.menu = elem.querySelector('ul');
+ this.menu = elem.querySelector('ul, [dropdown-menu]');
this.toggle = elem.querySelector('[dropdown-toggle]');
this.setupListeners();
}
this.elem = elem;
this.search = '';
this.lastClick = 0;
+ this.selectedItemData = null;
- let entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
- let entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
+ const entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
+ const entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
this.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}&permission=${encodeURIComponent(entityPermission)}`);
this.input = elem.querySelector('[entity-selector-input]');
this.searchInput = elem.querySelector('[entity-selector-search]');
this.loading = elem.querySelector('[entity-selector-loading]');
this.resultsContainer = elem.querySelector('[entity-selector-results]');
+ this.addButton = elem.querySelector('[entity-selector-add-button]');
this.elem.addEventListener('click', this.onClick.bind(this));
this.searchEntities(this.searchInput.value);
}, 200);
});
+
this.searchInput.addEventListener('keydown', event => {
if (event.keyCode === 13) event.preventDefault();
});
+ if (this.addButton) {
+ this.addButton.addEventListener('click', event => {
+ if (this.selectedItemData) {
+ this.confirmSelection(this.selectedItemData);
+ this.unselectAll();
+ }
+ });
+ }
+
this.showLoading();
this.initialLoad();
}
searchEntities(searchTerm) {
this.input.value = '';
- let url = this.searchUrl + `&term=${encodeURIComponent(searchTerm)}`;
+ let url = `${this.searchUrl}&term=${encodeURIComponent(searchTerm)}`;
window.$http.get(url).then(resp => {
this.resultsContainer.innerHTML = resp.data;
this.hideLoading();
}
onClick(event) {
- let t = event.target;
-
- if (t.matches('.entity-list-item *')) {
+ const listItem = event.target.closest('[data-entity-type]');
+ if (listItem) {
event.preventDefault();
event.stopPropagation();
- let item = t.closest('[data-entity-type]');
- this.selectItem(item);
- } else if (t.matches('[data-entity-type]')) {
- this.selectItem(t)
+ this.selectItem(listItem);
}
-
}
selectItem(item) {
- let isDblClick = this.isDoubleClick();
- let type = item.getAttribute('data-entity-type');
- let id = item.getAttribute('data-entity-id');
- let isSelected = !item.classList.contains('selected') || isDblClick;
+ const isDblClick = this.isDoubleClick();
+ const type = item.getAttribute('data-entity-type');
+ const id = item.getAttribute('data-entity-id');
+ const isSelected = (!item.classList.contains('selected') || isDblClick);
this.unselectAll();
this.input.value = isSelected ? `${type}:${id}` : '';
- if (!isSelected) window.$events.emit('entity-select-change', null);
+ const link = item.getAttribute('href');
+ const name = item.querySelector('.entity-list-item-name').textContent;
+ const data = {id: Number(id), name: name, link: link};
+
if (isSelected) {
item.classList.add('selected');
- item.classList.add('primary-background');
+ this.selectedItemData = data;
+ } else {
+ window.$events.emit('entity-select-change', null)
}
+
if (!isDblClick && !isSelected) return;
- let link = item.querySelector('.entity-list-item-link').getAttribute('href');
- let name = item.querySelector('.entity-list-item-name').textContent;
- let data = {id: Number(id), name: name, link: link};
+ if (isDblClick) {
+ this.confirmSelection(data);
+ }
+ if (isSelected) {
+ window.$events.emit('entity-select-change', data)
+ }
+ }
- if (isDblClick) window.$events.emit('entity-select-confirm', data);
- if (isSelected) window.$events.emit('entity-select-change', data);
+ confirmSelection(data) {
+ window.$events.emit('entity-select-confirm', data);
}
unselectAll() {
let selected = this.elem.querySelectorAll('.selected');
- for (let i = 0, len = selected.length; i < len; i++) {
- selected[i].classList.remove('selected');
- selected[i].classList.remove('primary-background');
+ for (let selectedElem of selected) {
+ selectedElem.classList.remove('selected', 'primary-background');
}
+ this.selectedItemData = null;
}
}
constructor(elem) {
this.elem = elem;
- this.isOpen = false;
+
+ // Component state
+ this.isOpen = elem.getAttribute('expand-toggle-is-open') === 'yes';
+ this.updateEndpoint = elem.getAttribute('expand-toggle-update-endpoint');
this.selector = elem.getAttribute('expand-toggle');
+
+ // Listener setup
elem.addEventListener('click', this.click.bind(this));
}
click(event) {
event.preventDefault();
- let matchingElems = document.querySelectorAll(this.selector);
- for (let i = 0, len = matchingElems.length; i < len; i++) {
- this.isOpen ? this.close(matchingElems[i]) : this.open(matchingElems[i]);
+
+ const matchingElems = document.querySelectorAll(this.selector);
+ for (let match of matchingElems) {
+ this.isOpen ? this.close(match) : this.open(match);
}
+
this.isOpen = !this.isOpen;
+ this.updateSystemAjax(this.isOpen);
+ }
+
+ updateSystemAjax(isOpen) {
+ window.$http.patch(this.updateEndpoint, {
+ expand: isOpen ? 'true' : 'false'
+ });
}
}
--- /dev/null
+
+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;
\ No newline at end of file
import pageDisplay from "./page-display";
import shelfSort from "./shelf-sort";
import homepageControl from "./homepage-control";
-
+import headerMobileToggle from "./header-mobile-toggle";
+import listSortControl from "./list-sort-control";
+import triLayout from "./tri-layout";
+import breadcrumbListing from "./breadcrumb-listing";
+import permissionsTable from "./permissions-table";
const componentMapping = {
'dropdown': dropdown,
'page-display': pageDisplay,
'shelf-sort': shelfSort,
'homepage-control': homepageControl,
+ 'header-mobile-toggle': headerMobileToggle,
+ 'list-sort-control': listSortControl,
+ 'tri-layout': triLayout,
+ 'breadcrumb-listing': breadcrumbListing,
+ 'permissions-table': permissionsTable,
};
window.components = {};
window.components.init = initAll;
-export default initAll;
\ No newline at end of file
+export default initAll;
--- /dev/null
+/**
+ * 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;
\ No newline at end of file
let action = button.getAttribute('data-action');
if (action === 'insertImage') this.actionInsertImage();
if (action === 'insertLink') this.actionShowLinkSelector();
- if (action === 'insertDrawing' && event.ctrlKey) {
+ if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
this.actionShowImageManager();
return;
}
if (action === 'insertDrawing') this.actionStartDrawing();
});
+ // Mobile section toggling
+ this.elem.addEventListener('click', event => {
+ const toolbarLabel = event.target.closest('.editor-toolbar-label');
+ if (!toolbarLabel) return;
+
+ const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
+ for (let activeElem of currentActiveSections) {
+ activeElem.classList.remove('active');
+ }
+
+ toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
+ });
+
window.$events.listen('editor-markdown-update', value => {
this.cm.setValue(value);
this.updateAndRender();
elem.addEventListener('click', event => {
if (event.target === elem) return this.hide();
});
- let closeButtons = elem.querySelectorAll('.overlay-close');
+ let closeButtons = elem.querySelectorAll('.popup-header-close');
for (let i=0; i < closeButtons.length; i++) {
closeButtons[i].addEventListener('click', this.hide.bind(this));
}
commentElem.querySelector('[comment-edit-container]').style.display = 'block';
let textArea = commentElem.querySelector('[comment-edit-container] textarea');
let lineCount = textArea.value.split('\n').length;
- textArea.style.height = (lineCount * 20) + 'px';
+ textArea.style.height = ((lineCount * 20) + 40) + 'px';
this.editingComment = commentElem;
}
commentElem.parentNode.removeChild(commentElem);
window.$events.emit('success', window.trans('entities.comment_deleted_success'));
this.updateCount();
+ this.hideForm();
});
}
showForm() {
this.formContainer.style.display = 'block';
this.formContainer.parentNode.style.display = 'block';
- this.elem.querySelector('[comment-add-button]').style.display = 'none';
+ this.elem.querySelector('[comment-add-button-container]').style.display = 'none';
this.formInput.focus();
window.scrollToElement(this.formInput);
}
hideForm() {
this.formContainer.style.display = 'none';
this.formContainer.parentNode.style.display = 'none';
- this.elem.querySelector('[comment-add-button]').style.display = 'block';
+ const addButtonContainer = this.elem.querySelector('[comment-add-button-container]');
+ if (this.getCommentCount() > 0) {
+ this.elem.appendChild(addButtonContainer)
+ } else {
+ const countBar = this.elem.querySelector('[comment-count-bar]');
+ countBar.appendChild(addButtonContainer);
+ }
+ addButtonContainer.style.display = 'block';
+ }
+
+ getCommentCount() {
+ return this.elem.querySelectorAll('.comment-box[comment]').length;
}
setReply(commentElem) {
let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
// observe each heading
- for (let i = 0; i !== headings.length; ++i) {
- pageNavObserver.observe(headings[i]);
+ for (let heading of headings) {
+ pageNavObserver.observe(heading);
}
}
}
function toggleAnchorHighlighting(elementId, shouldHighlight) {
- let anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
- for (let i = 0; i < anchorsToHighlight.length; i++) {
- // Change below to use classList.toggle when IE support is dropped.
- if (shouldHighlight) {
- anchorsToHighlight[i].classList.add('current-heading');
- } else {
- anchorsToHighlight[i].classList.remove('current-heading');
- }
+ const anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
+ for (let anchor of anchorsToHighlight) {
+ anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
}
}
}
--- /dev/null
+
+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;
\ No newline at end of file
constructor(elem) {
this.elem = elem;
- this.input = elem.querySelector('input');
+ this.input = elem.querySelector('input[type=hidden]');
+ this.checkbox = elem.querySelector('input[type=checkbox]');
- this.elem.onclick = this.onClick.bind(this);
+ this.checkbox.addEventListener('change', this.onClick.bind(this));
}
onClick(event) {
- let checked = this.input.value !== 'true';
+ let checked = this.checkbox.checked;
this.input.value = checked ? 'true' : 'false';
- checked ? this.elem.classList.add('active') : this.elem.classList.remove('active');
}
}
--- /dev/null
+
+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;
\ No newline at end of file
plugins: this.plugins,
imagetools_toolbar: 'imageoptions',
toolbar: this.getToolBar(),
- content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
+ content_style: "html, body {background: #FFF;} body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
style_formats: [
{title: "Header Large", format: "h2"},
{title: "Header Medium", format: "h3"},
if (scrollId) {
scrollToText(scrollId);
}
+
+ // Override for touch events to allow scroll on mobile
+ const container = editor.getContainer();
+ const toolbarButtons = container.querySelectorAll('.mce-btn');
+ for (let button of toolbarButtons) {
+ button.addEventListener('touchstart', event => {
+ event.stopPropagation();
+ });
+ }
+ window.editor = editor;
});
function editorChange() {
// Paste image-uploads
editor.on('paste', event => editorPaste(event, editor, context));
+
}
};
}
}
}
-.anim.menuIn {
- transform-origin: 100% 0%;
- animation-name: menuIn;
- animation-duration: 120ms;
- animation-delay: 0s;
- animation-timing-function: cubic-bezier(.62, .28, .23, .99);
-}
-
-@keyframes menuIn {
- from {
- opacity: 0;
- transform: scale3d(0, 0, 1);
- }
-
- to {
- opacity: 1;
- transform: scale3d(1, 1, 1);
- }
-}
-
@keyframes loadingBob {
0% {
transform: translate3d(0, 0, 0);
animation-duration: 180ms;
animation-delay: 0s;
animation-timing-function: cubic-bezier(.62, .28, .23, .99);
-}
-
-.selectFade {
- transition: background-color ease-in-out 3000ms;
}
\ No newline at end of file
-/*
-* This file container all block styling including background shading,
-* margins, paddings & borders.
-*/
-
-
-/*
-* Background Shading
-*/
-.shaded {
- background-color: #f1f1f1;
- &.pos {
- background-color: lighten($positive, 40%);
- }
- &.neg {
- background-color: lighten($negative, 20%);
- }
- &.primary {
- background-color: lighten($primary, 40%);
- }
- &.secondary {
- background-color: lighten($secondary, 30%);
- }
-}
-
-/*
-* Bordering
-*/
-.bordered {
- border: 1px solid #BBB;
- &.pos {
- border-color: $positive;
- }
- &.neg {
- border-color: $negative;
- }
- &.primary {
- border-color: $primary;
- }
- &.secondary {
- border-color: $secondary;
- }
- &.thick {
- border-width: 2px;
- }
-}
-.rounded {
- border-radius: 3px;
-}
-
-/*
-* Padding
-*/
-.nopadding {
- padding: 0;
-}
-.padded {
- padding: $-l;
- &.large {
- padding: $-xl;
- }
- >h1, >h2, >h3, >h4 {
- &:first-child {
- margin-top: 0.1em;
- }
- }
-}
-.padded-vertical, .padded-top {
- padding-top: $-m;
- &.large {
- padding-top: $-xl;
- }
-}
-
-.padded-vertical, .padded-bottom {
- padding-bottom: $-m;
- &.large {
- padding-bottom: $-xl;
- }
-}
-.padded-horizontal, .padded-left {
- padding-left: $-m;
- &.large {
- padding-left: $-xl;
- }
-}
-.padded-horizontal, .padded-right {
- padding-right: $-m;
- &.large {
- padding-right: $-xl;
- }
-}
-
-/*
-* Margins
-*/
-.margins {
- margin: $-l;
- &.large {
- margin: $-xl;
- }
-}
-.margins-vertical, .margin-top {
- margin-top: $-m;
- &.large {
- margin-top: $-xl;
- }
-}
-.margins-vertical, .margin-bottom {
- margin-bottom: $-m;
- &.large {
- margin-bottom: $-xl;
- }
-}
-.margins-horizontal, .margin-left {
- margin-left: $-m;
- &.large {
- margin-left: $-xl;
- }
-}
-.margins-horizontal, .margin-right {
- margin-right: $-m;
- &.large {
- margin-right: $-xl;
- }
-}
-
-
/**
* Callouts
*/
-
.callout {
border-left: 3px solid #BBB;
background-color: #EEE;
}
}
+/**
+ * Card-style blocks
+ */
+
.card {
- margin: $-m;
background-color: #FFF;
- box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.2);
+ box-shadow: $bs-card;
+ border-radius: 3px;
+ border: 1px solid transparent;
h3 {
- padding: $-m;
- border-bottom: 1px solid #E8E8E8;
+ padding: $-m $-m $-xs;
margin: 0;
- font-size: $fs-s;
- color: #888;
- fill: #888;
+ font-size: $fs-m;
+ color: #222;
+ fill: #222;
font-weight: 400;
- text-transform: uppercase;
}
h3 a {
line-height: 1;
}
}
-.sidebar .card {
- h3, .body, .empty-text {
- padding: $-s $-m;
- }
-}
-
.card.drag-card {
border: 1px solid #DDD;
border-radius: 4px;
display: flex;
- padding: 0;
- padding-left: $-s + 28px;
+ padding: 0 0 0 ($-s + 28px);
margin: $-s 0;
position: relative;
.drag-card-action {
}
.handle, .drag-card-action {
display: flex;
- padding: 0;
align-items: center;
text-align: center;
justify-content: center;
width: 28px;
flex-grow: 0;
- padding-left: $-xs;
- padding-right: $-xs;
+ padding: 0 $-xs;
&:hover {
background-color: #EEE;
}
margin: $-s 0;
width: 100%;
}
- > div.padded {
- padding: $-s 0 !important;
- }
.handle {
background-color: #EEE;
left: 0;
}
}
-.well {
- background-color: #F8F8F8;
- padding: $-m;
- border: 1px solid #DDD;
+.grid-card {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid #ddd;
+ margin-bottom: $-l;
+ border-radius: 4px;
+ overflow: hidden;
+ min-width: 100px;
+ color: $text-dark;
+ transition: border-color ease-in-out 120ms, box-shadow ease-in-out 120ms;
+ &:hover {
+ color: $text-dark;
+ text-decoration: none;
+ box-shadow: $bs-card;
+ }
+ h2 {
+ width: 100%;
+ font-size: 1.5em;
+ margin: 0 0 10px;
+ }
+ p {
+ font-size: .7rem;
+ margin: 0;
+ line-height: 1.6em;
+ }
+ .grid-card-content {
+ flex: 1;
+ border-top: 0;
+ border-bottom-width: 2px;
+ }
+ .grid-card-content, .grid-card-footer {
+ padding: $-l;
+ }
+ .grid-card-content + .grid-card-footer {
+ padding-top: 0;
+ }
+}
+
+.bookshelf-grid-item .grid-card-content h2 a {
+ color: $color-bookshelf;
+ fill: $color-bookshelf;
}
+.book-grid-item .grid-card-footer {
+ p.small {
+ font-size: .8em;
+ margin: 0;
+ }
+}
+
+.content-wrap.card {
+ padding: $-m $-xxl;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: $-xl;
+ overflow: auto;
+ min-height: 60vh;
+ &.auto-height {
+ min-height: 0;
+ }
+ &.fill-width {
+ width: 100%;
+ }
+}
+@include smaller-than($xxl) {
+ .content-wrap.card {
+ padding: $-l $-xl;
+ }
+}
+@include smaller-than($m) {
+ .content-wrap.card {
+ padding: $-m $-l;
+ }
+}
+@include smaller-than($s) {
+ .content-wrap.card {
+ padding: $-m $-s;
+ }
+}
+
+/**
+ * Tags
+ */
.tag-item {
display: inline-flex;
margin-bottom: $-xs;
+button {
+ font-size: 100%;
+}
@mixin generate-button-colors($textColor, $backgroundColor) {
background-color: $backgroundColor;
color: $textColor;
fill: $textColor;
- text-transform: uppercase;
border: 1px solid $backgroundColor;
- vertical-align: top;
&:hover {
background-color: lighten($backgroundColor, 8%);
- //box-shadow: $bs-med;
- text-decoration: none;
color: $textColor;
}
&:active {
&:focus {
background-color: lighten($backgroundColor, 4%);
box-shadow: $bs-light;
- text-decoration: none;
color: $textColor;
}
}
// Button Specific Variables
$button-border-radius: 2px;
-.button-base {
+.button {
text-decoration: none;
- font-size: $fs-m;
+ font-size: 0.85rem;
line-height: 1.4em;
padding: $-xs*1.3 $-m;
- margin: $-xs $-xs $-xs 0;
+ margin-top: $-xs;
+ margin-bottom: $-xs;
display: inline-block;
- border: none;
font-weight: 400;
outline: 0;
border-radius: $button-border-radius;
cursor: pointer;
- transition: all ease-in-out 120ms;
- box-shadow: 0;
- @include generate-button-colors(#EEE, $primary);
-}
-
-.button, input[type="button"], input[type="submit"] {
- @extend .button-base;
- &.pos {
- @include generate-button-colors(#EEE, $positive);
- }
- &.neg {
- @include generate-button-colors(#EEE, $negative);
- }
- &.secondary {
- @include generate-button-colors(#EEE, $secondary);
- }
- &.muted {
- @include generate-button-colors(#EEE, #AAA);
+ transition: background-color ease-in-out 120ms, box-shadow ease-in-out 120ms;
+ box-shadow: none;
+ background-color: $primary;
+ color: #FFF;
+ fill: #FFF;
+ text-transform: uppercase;
+ border: 1px solid $primary;
+ vertical-align: top;
+ &:hover, &:focus {
+ text-decoration: none;
}
- &.muted-light {
- @include generate-button-colors(#666, #e4e4e4);
+ &:active {
+ background-color: darken($primary, 8%);
}
}
-
+.button.primary {
+ @include generate-button-colors(#FFFFFF, $primary);
+}
.button.outline {
background-color: transparent;
color: #888;
box-shadow: none;
background-color: #EEE;
}
- &.page {
- border-color: $color-page;
- color: $color-page;
- fill: $color-page;
- &:hover, &:focus, &:active {
- background-color: $color-page;
- color: #FFF;
- fill: #FFF;
- }
- }
- &.chapter {
- border-color: $color-chapter;
- color: $color-chapter;
- fill: $color-chapter;
- &:hover, &:focus, &:active {
- background-color: $color-chapter;
- color: #FFF;
- fill: #FFF;
- }
- }
- &.book {
- border-color: $color-book;
- color: $color-book;
- fill: $color-book;
- &:hover, &:focus, &:active {
- background-color: $color-book;
- color: #FFF;
- fill: #FFF;
- }
- }
+}
+
+.button + .button {
+ margin-left: $-s;
+}
+
+.button.small {
+ font-size: 0.75rem;
+ padding: $-xs*1.2 $-s;
}
.text-button {
- @extend .link;
+ cursor: pointer;
background-color: transparent;
padding: 0;
margin: 0;
border: none;
user-select: none;
+ font-size: 0.75rem;
+ line-height: 1.4em;
&:focus, &:active {
outline: 0;
}
&:hover {
text-decoration: none;
}
- &.neg {
- color: $negative;
- }
-}
-
-.button-group {
- @include clearfix;
- .button, button[type="button"] {
- margin: $-xs 0 $-xs 0;
- float: left;
- border-radius: 0;
- &:first-child {
- border-radius: $button-border-radius 0 0 $button-border-radius;
- }
- &:last-child {
- border-radius: 0 $button-border-radius $button-border-radius 0;
- }
- }
}
.button.block {
width: 100%;
- text-align: center;
+ text-align: left;
display: block;
- &.text-left {
- text-align: left;
- }
}
.button.icon {
width: 24px;
height: 24px;
}
- padding: $-s $-m;
- padding-bottom: $-s - 2px;
- padding-left: $-m*2 + 24px;
+ padding: $-s $-m ($-s - 2px) ($-m*2 + 24px);
}
.button[disabled] {
--- /dev/null
+
+/*
+ * 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;
+}
\ No newline at end of file
transition: all ease-in-out 180ms;
user-select: none;
svg[data-icon="caret-right"] {
+ margin-right: 0;
+ font-size: 1rem;
transition: all ease-in-out 180ms;
transform: rotate(0deg);
- transform-origin: 25% 50%;
+ transform-origin: 50% 50%;
}
&.open svg[data-icon="caret-right"] {
transform: rotate(90deg);
}
+ svg[data-icon="caret-right"] + * {
+ margin-left: $-xs;
+ }
}
[overlay] {
}
}
-.corner-button {
+.popup-footer button, .popup-header-close {
position: absolute;
top: 0;
right: 0;
height: 40px;
border-radius: 0;
box-shadow: none;
+ &:active {
+ outline: 0;
+ }
+}
+.popup-header-close {
+ background-color: transparent;
+ border: 0;
+ color: #FFF;
+ font-size: 16px;
+ padding: 0 $-m;
}
.popup-header, .popup-footer {
padding: 8px $-m;
}
}
+.popup-footer {
+ margin-top: 1px;
+}
body.flexbox-support #entity-selector-wrap .popup-body .form-group {
height: 444px;
min-height: 444px;
#entity-selector-wrap .popup-body .form-group {
margin: 0;
}
+.popup-body .entity-selector-container {
+ flex: 1;
+}
.image-manager-body {
min-height: 70vh;
}
.comment-box {
- clear: left;
border: 1px solid #DDD;
- margin-bottom: $-s;
- border-radius: 3px;
+ border-radius: 4px;
+ background-color: #FFF;
.content {
- padding: $-s;
font-size: 0.666em;
p, ul, ol {
font-size: $fs-m;
margin: .5em 0;
}
}
- .reply-row {
- padding: $-xs $-s;
+ .actions {
+ opacity: 0;
+ transition: opacity ease-in-out 120ms;
+ }
+ &:hover .actions {
+ opacity: 1;
}
}
.comment-box .header {
- padding: $-xs $-s;
- background-color: #f8f8f8;
- border-bottom: 1px solid #DDD;
.meta {
img, a, span {
display: inline-block;
#tag-manager .drag-card {
max-width: 500px;
+}
+
+.permissions-table [permissions-table-toggle-all-in-row] {
+ display: none;
+}
+.permissions-table tr:hover [permissions-table-toggle-all-in-row] {
+ display: inline;
}
\ No newline at end of file
}
}
+@include smaller-than($m) {
+ #markdown-editor {
+ flex-direction: column;
+ }
+ #markdown-editor .markdown-editor-wrap {
+ width: 100%;
+ max-width: 100%;
+ }
+ #markdown-editor .editor-toolbar {
+ padding: 0;
+ }
+ #markdown-editor .editor-toolbar > * {
+ padding: $-xs $-s;
+ }
+ .editor-toolbar-label {
+ float: none !important;
+ border-bottom: 1px solid #DDD;
+ display: block;
+ }
+ .markdown-editor-wrap:not(.active) .editor-toolbar + div, .markdown-editor-wrap:not(.active) .editor-toolbar .buttons {
+ display: none;
+ }
+ #markdown-editor .markdown-editor-wrap:not(.active) {
+ flex-grow: 0;
+ flex: none;
+ }
+}
+
.markdown-display {
padding: 0 $-m 0;
margin-left: -1px;
line-height: 1.4em;
font-size: 0.94em;
font-weight: 400;
- color: #999;
+ color: #666;
padding-bottom: 2px;
margin-bottom: 0.2em;
&.inline {
}
.toggle-switch {
- display: inline-block;
- background-color: #BBB;
- width: 36px;
- height: 14px;
- border-radius: 7px;
- position: relative;
- transition: all ease-in-out 120ms;
- cursor: pointer;
user-select: none;
- &:after {
- content: '';
- display: block;
- position: relative;
- left: 0;
- margin-top: -3px;
- width: 20px;
- height: 20px;
- border-radius: 50%;
- background-color: #fafafa;
- border: 1px solid #CCC;
- box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
- transition: all ease-in-out 120ms;
- }
- &.active {
- background-color: rgba($positive, 0.4);
- &:after {
- left: 16px;
- background-color: $positive;
- border: darken($positive, 20%);
+ display: inline-grid;
+ grid-template-columns: (16px + $-s) 1fr;
+ align-items: center;
+ margin: $-m 0;
+ .custom-checkbox {
+ width: 16px;
+ height: 16px;
+ border-radius: 2px;
+ display: inline-block;
+ border: 2px solid currentColor;
+ opacity: 0.6;
+ overflow: hidden;
+ fill: currentColor;
+ .svg-icon {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ bottom: auto;
+ top: -1.5px;
+ left: 0;
+ transition: transform ease-in-out 120ms;
+ transform: scale(0);
+ transform-origin: center center;
}
}
+ input[type=checkbox] {
+ display: none;
+ }
+ input[type=checkbox]:checked + .custom-checkbox .svg-icon {
+ transform: scale(1);
+ }
+ .custom-checkbox:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ opacity: 0.8;
+ }
}
-.toggle-switch-checkbox {
- display: none;
-}
-input:checked + .toggle-switch {
- background-color: rgba($positive, 0.4);
- &:after {
- left: 16px;
- background-color: $positive;
- border: darken($positive, 20%);
+.toggle-switch-list {
+ .toggle-switch {
+ margin: $-xs 0;
+ }
+ &.compact .toggle-switch {
+ margin: 1px 0;
}
}
.form-group {
margin-bottom: $-s;
- textarea {
- display: block;
+}
+
+.setting-list > div {
+ border-bottom: 1px solid #DDD;
+ padding: $-xl 0;
+ &:last-child {
+ border-bottom: none;
+ }
+}
+.setting-list-label {
+ color: #222;
+ font-size: 1rem;
+}
+.setting-list-label + p.small {
+ margin-bottom: 0;
+}
+.setting-list-label + .grid {
+ margin-top: $-m;
+}
+
+.setting-list .grid, .stretch-inputs {
+ input[type=text], input[type=email], input[type=password], select {
width: 100%;
- min-height: 64px;
}
}
font-family: monospace;
font-size: 12px;
min-height: 100px;
+ display: block;
+ width: 100%;
}
.form-group {
}
.form-group[collapsible] {
- margin-left: -$-m;
- margin-right: -$-m;
padding: 0 $-m;
- border-top: 1px solid #DDD;
- border-bottom: 1px solid #DDD;
+ border: 1px solid #DDD;
+ border-radius: 4px;
.collapse-title {
margin-left: -$-m;
margin-right: -$-m;
&.open .collapse-title label:before {
transform: rotate(90deg);
}
- &+.form-group[collapsible] {
- margin-top: -($-s + 1);
- }
}
.inline-input-style {
width: 300px;
max-width: 100%;
}
+ &.flexible input {
+ width: 100%;
+ }
+ .search-box-cancel {
+ left: auto;
+ right: 0;
+ }
}
.outline > input {
}
}
-#login-form label[for="remember"] {
- margin: 0;
-}
-#login-form label.toggle-switch {
- margin-left: $-xl;
-}
-
.image-picker img {
background-color: #BBB;
}
+++ /dev/null
-
-/** 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;
-}
* Includes the main navigation header and the faded toolbar.
*/
+header .grid {
+ grid-template-columns: auto min-content auto;
+}
+
+@include smaller-than($l) {
+ header .grid {
+ grid-template-columns: 1fr;
+ grid-row-gap: 0;
+ }
+}
+
header {
+ position: relative;
display: block;
- z-index: 2;
+ z-index: 6;
top: 0;
background-color: $primary-dark;
color: #fff;
fill: #fff;
- .padded {
- padding: $-m;
- }
border-bottom: 1px solid #DDD;
+ box-shadow: $bs-card;
+ padding: $-xxs 0;
.links {
display: inline-block;
vertical-align: top;
- margin-left: $-m;
}
.links a {
display: inline-block;
padding-left: $-m;
padding-right: 0;
}
- @include smaller-than($screen-md) {
- .links a {
- padding-left: $-s;
- padding-right: $-s;
- }
- .dropdown-container {
- padding-left: $-s;
- }
- }
.avatar, .user-name {
display: inline-block;
}
padding-top: 4px;
font-size: 18px;
}
- @include smaller-than($screen-md) {
+ @include between($l, $xl) {
padding-left: $-xs;
.name {
display: none;
}
}
}
- @include smaller-than($screen-sm) {
- text-align: center;
- .float.right {
- float: none;
- }
- .links a {
- padding: $-s;
- }
- .user-name {
- padding-top: $-s;
- }
- }
}
+
+
.header-search {
display: inline-block;
}
margin-top: 10px;
input {
background-color: rgba(0, 0, 0, 0.2);
- border: 1px solid rgba(255, 255, 255, 0.3);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: 40px;
color: #EEE;
z-index: 2;
+ padding-left: 40px;
}
button {
fill: #EEE;
z-index: 1;
+ left: 16px;
svg {
margin-right: 0;
}
:-moz-placeholder { /* Firefox 18- */
color: #DDD;
}
- @include smaller-than($screen-lg) {
- max-width: 250px;
- }
- @include smaller-than($l) {
+ @include between($l, $xl) {
max-width: 200px;
}
}
-@include smaller-than($s) {
- .header-search {
- display: block;
- }
-}
-
.logo {
display: inline-block;
&:hover {
height: 43px;
}
-.breadcrumbs span.sep {
- color: #aaa;
+.mobile-menu-toggle {
+ color: #FFF;
+ fill: #FFF;
+ font-size: 2em;
+ border: 2px solid rgba(255, 255, 255, 0.8);
+ border-radius: 4px;
padding: 0 $-xs;
+ position: absolute;
+ right: $-m;
+ top: 13px;
+ line-height: 1;
+ cursor: pointer;
+ user-select: none;
+ svg {
+ margin: 0;
+ bottom: -2px;
+ }
}
+
+@include smaller-than($l) {
+ header .header-links {
+ display: none;
+ background-color: #FFF;
+ z-index: 10;
+ right: $-m;
+ border-radius: 4px;
+ overflow: hidden;
+ position: absolute;
+ box-shadow: $bs-hover;
+ margin-top: -$-xs;
+ &.show {
+ display: block;
+ }
+ }
+ header .links a, header .dropdown-container ul li a {
+ text-align: left;
+ display: block;
+ padding: $-s $-m;
+ color: $text-dark;
+ fill: $text-dark;
+ svg {
+ margin-right: $-s;
+ }
+ &:hover {
+ background-color: #EEE;
+ color: #444;
+ fill: #444;
+ text-decoration: none;
+ }
+ }
+ header .dropdown-container {
+ display: block;
+ padding-left: 0;
+ }
+ header .links {
+ display: block;
+ }
+ header .dropdown-container ul {
+ display: block !important;
+ position: relative;
+ background-color: transparent;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ box-shadow: none;
+ }
+}
+
+.tri-layout-mobile-tabs {
+ position: sticky;
+ top: 0;
+ z-index: 5;
+ background-color: #FFF;
+ border-bottom: 1px solid #DDD;
+ box-shadow: $bs-card;
+}
+.tri-layout-mobile-tab {
+ text-align: center;
+ border-bottom: 3px solid #BBB;
+ &:first-child {
+ border-right: 1px solid #DDD;
+ }
+ &.active {
+ border-bottom-color: currentColor;
+ }
+}
+
+.breadcrumbs {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex-wrap: wrap;
+ opacity: 0.7;
+ .icon-list-item {
+ width: auto;
+ padding-top: $-xs;
+ padding-bottom: $-xs;
+ }
+ .separator {
+ display: inline-block;
+ fill: #aaa;
+ font-size: 1.6em;
+ line-height: 0.8;
+ margin: -2px 0 0;
+ }
+ &:hover {
+ opacity: 1;
+ }
+}
+
+@include smaller-than($l) {
+ .breadcrumbs .icon-list-item {
+ padding: $-xs;
+ > span + span {
+ display: none;
+ }
+ > span:first-child {
+ margin-right: 0;
+ }
+ }
+}
+
+.breadcrumb-listing {
+ position: relative;
+ .breadcrumb-listing-toggle {
+ padding: 6px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ &:hover {
+ border-color: #DDD;
+ }
+ }
+ .svg-icon {
+ margin-right: 0;
+ }
+}
+
+.breadcrumb-listing-dropdown {
+ box-shadow: $bs-med;
+ overflow: hidden;
+ min-height: 100px;
+ width: 240px;
+ display: none;
+ position: absolute;
+ z-index: 80;
+ right: -$-m;
+ .breadcrumb-listing-search .svg-icon {
+ position: absolute;
+ left: $-s;
+ top: 11px;
+ fill: #888;
+ pointer-events: none;
+ }
+ .breadcrumb-listing-entity-list {
+ max-height: 400px;
+ overflow-y: scroll;
+ text-align: left;
+ }
+ input {
+ padding-left: $-xl;
+ border-radius: 0;
+ border: 0;
+ border-bottom: 1px solid #DDD;
+ }
+}
+
+@include smaller-than($m) {
+ .breadcrumb-listing-dropdown {
+ position: fixed;
+ right: auto;
+ left: $-m;
+ }
+ .breadcrumb-listing-dropdown .breadcrumb-listing-entity-list {
+ max-height: 240px;
+ }
+}
+
.faded {
a, button, span, span > div {
color: #666;
padding: $-s;
}
-.faded-small {
- color: #000;
- fill: #000;
- font-size: 0.9em;
- background-color: $primary-faded;
-}
-
-.toolbar-container {
- background-color: #FFF;
-}
-
-.breadcrumbs .text-button, .action-buttons .text-button {
+.action-buttons .text-button {
display: inline-block;
- padding: $-s;
+ padding: $-xs $-s;
&:last-child {
padding-right: 0;
}
}
@include smaller-than($m) {
- .breadcrumbs .text-button, .action-buttons .text-button {
+ .action-buttons .text-button {
padding: $-xs $-xs;
}
.action-buttons .dropdown-container:last-child a {
padding-left: $-xs;
}
- .breadcrumbs .text-button {
- font-size: 0;
- }
- .breadcrumbs .text-button svg {
- font-size: $fs-m;
- }
- .breadcrumbs a i {
- font-size: $fs-m;
- padding-right: 0;
- }
- .breadcrumbs span.sep {
- padding: 0 $-xxs;
- }
- .toolbar .col-xs-1:first-child {
- padding-right: 0;
- }
}
.nav-tabs {
border-bottom: 2px solid $primary;
}
}
-}
-.faded-small .nav-tabs a {
- padding: $-s $-m;
}
\ No newline at end of file
}
html {
- background-color: #FFFFFF;
height: 100%;
overflow-y: scroll;
+ background-color: #F2F2F2;
&.flexbox {
overflow-y: hidden;
}
- &.shaded {
- background-color: #F2F2F2;
- }
}
body {
font-size: $fs-m;
line-height: 1.6;
- color: #616161;
+ color: #444;
-webkit-font-smoothing: antialiased;
- &.shaded {
- background-color: #F2F2F2;
- }
-}
-
-button {
- font-size: 100%;
+ background-color: #F2F2F2;
}
\ No newline at end of file
--- /dev/null
+
+/**
+ * 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;
+ }
+}
\ No newline at end of file
-.page-list {
- h4 {
- margin: $-l 0 $-xs 0;
- font-size: 1.666em;
+
+.book-contents .entity-list-item {
+ .icon {
+ width: 4px;
+ border-radius: 1px;
+ justify-self: stretch;
+ align-self: stretch;
+ height: auto;
+ margin-right: $-l;
}
- a.chapter {
- color: $color-chapter;
+ .icon:after {
+ opacity: 0.5;
}
- .inset-list {
+ .icon svg {
display: none;
- overflow: hidden;
}
- h5 {
- display: block;
- margin: $-s 0 0 0;
- border-left: 5px solid $color-page;
- padding: $-xs 0 $-xs $-m;
- font-size: 1.1em;
- font-weight: normal;
- &.draft {
- border-left-color: $color-page-draft;
- }
- }
- .entity-list-item {
- margin-bottom: $-m;
- }
- hr {
- margin-top: 0;
- }
- .page, .chapter, .book {
- padding-left: $-l;
+ p {
+ margin-bottom: 0;
}
- .page {
- border-left: 5px solid $color-page;
+ .inner-page {
+ padding-top: 0;
+ padding-bottom: 0;
}
- .page.draft {
- border-left: 5px solid $color-page-draft;
- .text-page {
- color: $color-page-draft;
- fill: $color-page-draft;
+}
+
+.entity-list-item + .chapter-expansion {
+ display: flex;
+ padding: 0 $-m $-m $-m;
+ align-items: center;
+ border: 0;
+ width: 100%;
+ position: relative;
+ > .icon {
+ width: 4px;
+ height: auto;
+ border-radius: 0 0 1px 1px;
+ align-self: stretch;
+ flex-shrink: 0;
+ &:before {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ background-color: currentColor;
+ content: '';
+ opacity: 0.5;
+ }
+ &:after {
+ opacity: 0.5;
}
}
- .chapter {
- border-left: 5px solid $color-chapter;
+ .icon svg {
+ display: none;
}
- .book {
- border-left: 5px solid $color-book;
+ > .content {
+ flex: 1;
}
- .meta {
- margin-top: -$-m;
- font-size: 0.95em;
+ .chapter-expansion-toggle {
+ border-radius: 0 4px 4px 0;
+ padding: $-xs $-m;
}
- .meta span {
- margin-right: $-s;
+ .chapter-expansion-toggle:hover {
+ background-color: rgba(0, 0, 0, 0.06);
}
}
-@include smaller-than($s) {
- .page-list h4 {
- font-size: 1.333em;
+.entity-list-item.has-children {
+ padding-bottom: 0;
+ > .icon {
+ border-radius: 4px 4px 0 0;
+ }
+}
+
+.inset-list {
+ display: none;
+ .entity-list-item-name {
+ font-size: 1rem;
+ }
+ .entity-list-item-children {
+ padding-top: 0;
+ padding-bottom: 0;
}
}
.sidebar-page-nav {
- $nav-indent: $-s;
+ $nav-indent: $-m;
list-style: none;
- margin: $-s 0 $-m 2px;
- border-left: 2px dotted #BBB;
+ margin: $-s 0 $-m $-xs;
+ position: relative;
+ &:after {
+ content: '';
+ display: block;
+ position: absolute;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.2);
+ width: 2px;
+ top: 5px;
+ bottom: 5px;
+ z-index: 0;
+ }
li {
- padding-left: $-s;
margin-bottom: 4px;
font-size: 0.95em;
+ position: relative;
}
.h1 {
- margin-left: -2px;
+ padding-left: $nav-indent;
}
.h2 {
- margin-left: -2px;
+ padding-left: $nav-indent;
}
.h3 {
- margin-left: $nav-indent;
+ padding-left: $nav-indent * 2;
}
.h4 {
- margin-left: $nav-indent*2;
+ padding-left: $nav-indent * 2.5;
}
.h5 {
- margin-left: $nav-indent*3;
+ padding-left: $nav-indent*3;
}
.h6 {
- margin-left: $nav-indent*4;
+ padding-left: $nav-indent*3.5;
}
.current-heading {
font-weight: bold;
}
+ li:not(.current-heading) .sidebar-page-nav-bullet {
+ background-color: #BBB !important;
+ }
+ .sidebar-page-nav-bullet {
+ width: 6px;
+ height: 6px;
+ position: absolute;
+ left: -2px;
+ top: 30%;
+ border-radius: 50%;
+ box-shadow: 0 0 0 6px #F2F2F2;
+ z-index: 1;
+ }
}
// Sidebar list
-.book-tree {
- transition: ease-in-out 240ms;
- transition-property: right, border;
-}
-.book-tree h4 {
- padding: $-m $-s 0 $-s;
- i {
- padding-right: $-s;
- }
-}
-.book-tree .sidebar-page-list {
+.book-tree .sidebar-page-list {
list-style: none;
- margin: $-xs 0 0;
+ margin: $-xs -$-s 0 -$-s;
padding-left: 0;
- border-left: 5px solid $color-book;
- li a {
- display: block;
- border-bottom: none;
- padding: $-xs 0 $-xs $-s;
- &:hover {
- text-decoration: none;
- }
- }
- li a i {
- padding-right: $-xs + 2px;
- }
- li, a {
+ padding-right: 0;
+ position: relative;
+
+ &:after, .sub-menu:after {
+ content: '';
display: block;
+ position: absolute;
+ left: $-m;
+ top: 1rem;
+ bottom: 1rem;
+ border-left: 4px solid rgba(0, 0, 0, 0.1);
+ z-index: 0;
}
- a.bold {
- color: #EEE !important;
- fill: #EEE !important;
- }
+
ul {
list-style: none;
- margin: 0;
+ padding-left: 1rem;
+ padding-right: 0;
}
- .book {
- color: $color-book !important;
- fill: $color-book !important;
- &.selected {
- background-color: rgba($color-book, 0.29);
+ .entity-list-item {
+ padding-top: $-xxs;
+ padding-bottom: $-xxs;
+ .content {
+ padding-top: $-xs;
+ padding-bottom: $-xs;
+ max-width: calc(100% - 20px);
}
}
- .chapter {
- color: $color-chapter !important;
- fill: $color-chapter !important;
- &.selected {
- background-color: rgba($color-chapter, 0.12);
- }
+ .entity-list-item.no-hover {
+ margin-top: -$-xs;
+ padding-right: 0;
}
- .page {
- color: $color-page !important;
- fill: $color-page !important;
- border-bottom: none;
- &.selected {
- background-color: rgba($color-page, 0.1);
- }
+ .entity-list-item-name {
+ font-size: 1em;
+ margin: 0;
}
- [chapter-toggle] {
- padding-left: $-s;
+ .chapter-child-menu {
+ font-size: .8rem;
+ margin-top: -.2rem;
+ margin-left: -1rem;
}
- .list-item-chapter {
- border-left: 5px solid $color-chapter;
- margin: 10px 10px;
- display: block;
+ [chapter-toggle] {
+ padding-left: .7rem;
+ padding-bottom: .2rem;
}
- .list-item-page {
- border-bottom: none;
- border-left: 5px solid $color-page;
- margin: 10px 10px;
+ .entity-list-item .icon {
+ z-index: 2;
+ width: 4px;
+ height: auto;
+ align-self: stretch;
+ flex-shrink: 0;
+ border-radius: 1px;
+ opacity: 0.6;
}
- .list-item-page.draft {
- border-left: 5px solid $color-page-draft;
+ .entity-list-item .icon:after {
+ opacity: 1;
}
- .page.draft .page, .list-item-page.draft a.page {
- color: $color-page-draft !important;
- fill: $color-page-draft !important;
+ .entity-list-item .icon svg {
+ display: none;
}
- .sub-menu {
+}
+
+.chapter-child-menu {
+ ul.sub-menu {
display: none;
padding-left: 0;
+ position: relative;
}
[chapter-toggle].open + .sub-menu {
display: block;
// Sortable Lists
.sortable-page-list, .sortable-page-list ul {
list-style: none;
- background-color: #FFF;
}
.sort-box {
margin-bottom: $-m;
- padding: 0 $-l 0 $-l;
- border-left: 4px solid $color-book;
+ border: 2px solid rgba($color-book, 0.6);
+ padding: $-m $-xl;
+ border-radius: 4px;
+}
+.sort-box-options {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+.sort-box-options .button {
+ margin-left: 0;
}
.sortable-page-list {
margin-left: 0;
+ padding: 0;
+ .entity-list-item > span:first-child {
+ align-self: flex-start;
+ }
+ .entity-list-item > div {
+ display: block;
+ flex: 1;
+ }
> ul {
margin-left: 0;
}
ul {
- margin-bottom: 0;
+ margin-bottom: $-m;
margin-top: 0;
- box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.1);
+ padding-left: $-m;
}
li {
border: 1px solid #DDD;
- padding: $-xs $-s;
margin-top: -1px;
min-height: 38px;
&.text-chapter {
.activity-list-item {
padding: $-s 0;
+ display: grid;
+ grid-template-columns: min-content 1fr;
+ grid-column-gap: $-m;
color: #888;
fill: #888;
- border-bottom: 1px solid #EEE;
font-size: 0.9em;
- .left {
- float: left;
- }
- .left + .right {
- margin-left: 30px + $-s;
- }
- &:last-of-type {
- border-bottom: 0;
+}
+.card .activity-list-item {
+ padding: $-s $-m;
+}
+
+.user-list-item {
+ display: inline-grid;
+ padding: $-s;
+ grid-template-columns: min-content 1fr;
+ grid-column-gap: $-m;
+ font-size: 0.9em;
+ align-items: center;
+ > div:first-child {
+ line-height: 0;
}
}
margin: 0;
}
-.entity-list {
- > div {
- padding: $-m 0;
- }
+.entity-list, .icon-list {
+ margin: 0 (-$-m);
h4 {
margin: 0;
}
color: $color-page-draft;
fill: $color-page-draft;
}
+ > .dropdown-container {
+ display: block;
+ }
+}
+
+.icon-list hr {
+ margin: $-s $-m;
+ max-width: 140px;
+ opacity: 0.25;
+ height: 1.1px;
+}
+
+.icon-list hr + hr, .icon-list hr:first-child, .icon-list hr:last-child {
+ display: none;
+}
+
+.entity-list-item, .icon-list-item {
+ padding: $-s $-m;
+ display: flex;
+ align-items: center;
+ background-color: transparent;
+ border: 0;
+ width: 100%;
+ position: relative;
+ word-break: break-word;
+ h4 a {
+ color: #666;
+ }
+ > span:first-child {
+ margin-right: $-m;
+ flex-basis: 1.88em;
+ flex: none;
+ }
+ > span:last-child {
+ flex: 1;
+ text-align: left;
+ }
+ &:not(.no-hover) {
+ cursor: pointer;
+ }
+ &:not(.no-hover):hover {
+ text-decoration: none;
+ background-color: rgba(0, 0, 0, 0.1);
+ border-radius: 4px;
+ }
+ &.outline-hover {
+ border: 1px solid transparent;
+ }
+ &.outline-hover:hover {
+ background-color: transparent;
+ border-color: rgba(0, 0, 0, 0.1);
+ }
}
-.card .entity-list-item, .card .activity-list-item {
- padding-left: $-m;
- padding-right: $-m;
+.entity-list-item-path-sep {
+ display: inline-block;
+ vertical-align: top;
+ position: relative;
+ top: 1px;
+ svg {
+ margin-right: 0;
+ }
+}
+
+.card .entity-list-item:not(.no-hover):hover {
+ background-color: #F2F2F2;
+}
+.card .entity-list-item .entity-list-item:hover {
+ background-color: #EEEEEE;
+}
+
+.entity-list-item-children {
+ padding: $-m;
+ > div {
+ overflow: hidden;
+ padding: $-xs 0;
+ margin-top: -$-xs;
+ }
+ .entity-chip {
+ text-overflow: ellipsis;
+ height: 2.5em;
+ overflow: hidden;
+ text-align: left;
+ display: block;
+ white-space: nowrap;
+ }
+}
+
+.entity-list-item-image {
+ align-self: stretch;
+ width: 140px;
+ flex: none;
+ background-size: cover;
+ background-position: 50% 50%;
+ border-radius: 3px;
+ position: relative;
+ margin-right: $-l;
+
+ .svg-icon {
+ color: #FFF;
+ fill: #FFF;
+ font-size: 1.66rem;
+ margin-right: 0;
+ position: absolute;
+ bottom: $-xs;
+ left: $-xs;
+ }
+
+ @include smaller-than($m) {
+ width: 80px;
+ }
+}
+
+.chapter > .entity-list-item-image {
+ width: 60px;
}
.entity-list.compact {
- font-size: 0.6em;
+ font-size: 0.6 * $fs-m;
h4, a {
line-height: 1.2;
}
hr {
margin: 0;
}
+ @include smaller-than($m) {
+ h4 {
+ font-size: 1.666em;
+ }
+ }
}
.dropdown-container {
color: #999;
fill: #999;
}
- li.padded {
- padding: $-xs $-m;
- line-height: 1.2;
+ li.active a {
+ font-weight: 600;
}
a, button {
display: block;
.featured-image-container {
position: relative;
overflow: hidden;
- background: #F2F2F2;
+ min-height: 140px;
+ background-size: cover;
+ background-position: 50% 50%;
+ transition: opacity ease-in-out 240ms;
a {
display: block;
}
width: 100%;
max-width: 100%;
height: auto;
- transition: all .5s ease-in-out;
}
- img:hover {
- transform: scale(1.15);
- opacity: .5;
+}
+.featured-image-container-wrap {
+ position: relative;
+ .svg-icon {
+ color: #FFF;
+ fill: #FFF;
+ font-size: 2rem;
+ margin-right: 0;
+ position: absolute;
+ bottom: 10px;
+ left: 6px;
}
}
+.grid-card:hover .featured-image-container {
+ opacity: .5;
+}
+
+.action-link-list {
+ //padding: $-s 0;
+}
+.action-link {
+ background: transparent;
+ border: none;
+ color: currentColor;
+ padding: $-m 0;
+}
+.active-link-list {
+ a {
+ display: inline-block;
+ padding: $-s;
+ }
+ a:not(.active) {
+ color: #444;
+ fill: #444;
+ }
+ a:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ border-radius: 3px;
+ text-decoration: none;
+ }
+}
\ No newline at end of file
@mixin larger-than($size) {
@media screen and (min-width: $size) { @content; }
}
-@mixin clearfix() {
- &:after {
- display: block;
- content: '';
- font-size: 0;
- clear: both;
- position: relative;
- }
+@mixin between($min, $max) {
+ @media screen and (min-width: $min) and (max-width: $max) { @content; }
}
flex-direction: column;
align-items: stretch;
overflow: hidden;
- .faded-small {
- height: auto;
- }
+ background-color: #FFF;
+
.edit-area {
flex: 1;
flex-direction: column;
+ z-index: 1;
}
.mce-tinymce {
}
}
+@include smaller-than($l) {
+ .page-edit-toolbar {
+ overflow-x: scroll;
+ overflow-y: visible;
+ z-index: 4;
+ }
+ .page-edit-toolbar .grid.third {
+ display: block;
+ white-space: nowrap;
+ > div {
+ display: inline-block;
+ }
+ }
+}
+
+@include smaller-than($l) {
+ .page-edit-toolbar #save-button {
+ position: fixed;
+ z-index: 30;
+ background-color: #FFF;
+ border-radius: 50%;
+ width: 42px;
+ height: 42px;
+ font-size: 16px;
+ right: $-m;
+ bottom: $-xs;
+ box-shadow: $bs-med;
+ span {
+ display: none;
+ }
+ }
+}
+
.draft-notification {
pointer-events: none;
transform: scale(0);
width: 100%;
max-width: 840px;
margin: 0 auto;
- margin-top: $-xxl;
overflow-wrap: break-word;
- &.flex {
- margin-top: $-m;
- }
.align-left {
text-align: left;
}
min-height: 0px;
overflow-y: scroll;
}
- div[toolbox-tab-content] .padded {
- flex: 1;
- padding-top: 0;
- }
- div[toolbox-tab-content] .padded.files {
- overflow-x: hidden;
- }
h4 {
font-size: 24px;
margin: $-m 0 0 0;
}
}
-.comments-container {
- width: 100%;
- border-top: 1px solid #DDD;
- margin-top: $-xl;
- margin-bottom: $-m;
- h5 {
- color: #888;
- font-weight: normal;
- margin-top: 0.5em;
- }
+.comments-container h5 {
+ color: #888;
+ font-weight: normal;
+ margin-top: 0.5em;
}
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
.mce-open {
display: none;
}
+}
+
+.entity-list-item > span:first-child, .icon-list-item > span:first-child, .chapter-expansion > .icon {
+ font-size: 0.8rem;
+ width: 1.88em;
+ height: 1.88em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ border-radius: 1em;
+ position: relative;
+ overflow: hidden;
+ svg {
+ margin: 0;
+ bottom: 0;
+ }
+ &:after {
+ content: '';
+ position: absolute;
+ background-color: currentColor;
+ opacity: 0.2;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.entity-chip {
+ display: inline-block;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ font-size: 0.9em;
+ border-radius: 3px;
+ position: relative;
+ overflow: hidden;
+ padding: $-xs $-s;
+ fill: currentColor;
+ opacity: 0.85;
+ transition: opacity ease-in-out 120ms;
+ &:after {
+ content: '';
+ position: absolute;
+ background-color: currentColor;
+ opacity: 0.15;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ }
+ &:hover {
+ text-decoration: none;
+ opacity: 1;
+ }
}
\ No newline at end of file
--- /dev/null
+// 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')
\ No newline at end of file
table.table {
width: 100%;
- tr {
- border-bottom: 1px solid #DDD;
+ tr td, tr th {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
th, td {
text-align: left;
border: none;
- padding: $-xs $-xs;
+ padding: $-s $-s;
vertical-align: middle;
margin: 0;
}
td.actions {
overflow: visible;
}
+ a {
+ display: inline-block;
+ }
}
table.no-style {
font-weight: 400;
position: relative;
display: block;
- color: #555;
+ color: #222;
.subheader {
font-size: 0.5em;
line-height: 1em;
}
h5, h6 {
- font-weight: 500;
line-height: 1.2em;
margin-top: 0.78571429em;
margin-bottom: 0.66em;
}
}
+.list-heading {
+ font-size: 2rem;
+}
+
+h2.list-heading {
+ font-size: 1.333rem;
+}
+
/*
* Link styling
*/
-a, .link {
+a {
color: $primary;
cursor: pointer;
text-decoration: none;
}
small, p.small, span.small, .text-small {
- font-size: 0.8em;
- color: lighten($text-dark, 20%);
- small, p.small, span.small, .text-small {
- font-size: 1em;
- }
+ font-size: 0.75rem;
+ color: lighten($text-dark, 10%);
}
sup, .superscript {
display: block;
line-height: 1.6;
}
-/*
- * Text colors
- */
-p.pos, p .pos, span.pos, .text-pos {
- color: $positive;
- fill: $positive;
- &:hover {
- color: $positive;
- fill: $positive;
- }
-}
-
-p.neg, p .neg, span.neg, .text-neg {
- color: $negative;
- fill: $negative;
- &:hover {
- color: $negative;
- fill: $negative;
- }
-}
-
-p.muted, p .muted, span.muted, .text-muted {
- color: lighten($text-dark, 26%);
- fill: lighten($text-dark, 26%);
- &.small, .small {
- color: lighten($text-dark, 32%);
- fill: lighten($text-dark, 32%);
- }
-}
-
-p.primary, p .primary, span.primary, .text-primary {
- color: $primary;
- fill: $primary;
- &:hover {
- color: $primary;
- fill: $primary;
- }
-}
-
-p.secondary, p .secondary, span.secondary, .text-secondary {
- color: $secondary;
- fill: $secondary;
- &:hover {
- color: $secondary;
- fill: $secondary;
- }
-}
-
-.text-bookshelf {
- color: $color-bookshelf;
- fill: $color-bookshelf;
- &:hover {
- color: $color-bookshelf;
- fill: $color-bookshelf;
- }
-}
-.text-book {
- color: $color-book;
- fill: $color-book;
- &:hover {
- color: $color-book;
- fill: $color-book;
- }
-}
-.text-page {
- color: $color-page;
- fill: $color-page;
- &:hover {
- color: $color-page;
- fill: $color-page;
- }
- &.draft {
- color: $color-page-draft;
- fill: $color-page-draft;
- }
- &.draft:hover {
- color: $color-page-draft;
- fill: $color-page-draft;
- }
-}
-.text-chapter {
- color: $color-chapter;
- fill: $color-chapter;
- &:hover {
- color: $color-chapter;
- fill: $color-chapter;
- }
-}
-.faded .text-book:hover {
- color: $color-book !important;
- fill: $color-book !important;
-}
-.faded .text-chapter:hover {
- color: $color-chapter !important;
- fill: $color-chapter !important;
-}
-.faded .text-page:hover {
- color: $color-page !important;
- fill: $color-page !important;
-}
span.highlight {
//background-color: rgba($primary, 0.2);
/**
* Icons
*/
-i {
- padding-right: $-xs;
-}
-
.svg-icon {
width: 1em;
height: 1em;
position: relative;
bottom: -0.105em;
margin-right: $-xs;
+ pointer-events: none;
}
text-align: center;
}
+@include smaller-than($l) {
+ .mce-container-body.mce-flow-layout {
+ overflow-x: scroll;
+ white-space: nowrap;
+ }
+}
+
.edit-area.flex > div > .mce-tinymce.mce-container.mce-panel {
flex: 1 1 auto;
display: flex !important;
// Variables
///////////////
-// Sizes
-$max-width: 1400px;
-
// Screen breakpoints
+$xxl: 1400px;
$xl: 1100px;
$ipad-width: 1028px; // Is actually 1024 but we go over to ensure functionality.
$l: 1000px;
-$m: 800px;
+$m: 880px;
$s: 600px;
$xs: 400px;
$xxs: 360px;
$screen-md: 992px;
$screen-sm: 768px;
+// List of screen sizes
+$screen-sizes: (('xxs', $xxs), ('xs', $xs), ('s', $s), ('m', $m), ('l', $l), ('xl', $xl));
+
// Spacing (Margins+Padding)
$-xxxl: 64px;
$-xxl: 48px;
$-xs: 6px;
$-xxs: 3px;
+// List of our spacing sizes
+$spacing: (('none', 0), ('xxs', $-xxs), ('xs', $-xs), ('s', $-s), ('m', $-m), ('l', $-l), ('xl', $-xl), ('xxl', $-xxl));
+
// Fonts
$text: -apple-system, BlinkMacSystemFont,
"Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell",
sans-serif;
$mono: "Lucida Console", "DejaVu Sans Mono", "Ubunto Mono", Monaco, monospace;
$heading: $text;
-$fs-m: 15px;
-$fs-s: 14px;
+$fs-m: 14px;
+$fs-s: 12px;
// Colours
$primary: #0288D1;
// Item Colors
$color-bookshelf: #af5a5a;
$color-book: #009688;
-$color-chapter: #ef7c3c;
+$color-chapter: #d7804a;
$color-page: $primary;
$color-page-draft: #9A60DA;
// Shadows
$bs-light: 0 0 4px 1px #CCC;
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
-$bs-card: 0 1px 3px 1px rgba(76, 76, 76, 0.26), 0 1px 12px 0px rgba(76, 76, 76, 0.2);
+$bs-card: 0 1px 6px -1px rgba(0, 0, 0, 0.1);
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
\ No newline at end of file
@import "variables";
@import "mixins";
+@import "spacing";
@import "html";
@import "text";
-@import "grid";
+@import "layout";
@import "blocks";
@import "forms";
@import "tables";
body {
font-family: 'DejaVu Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+ background-color: #FFF;
+ margin: 0;
+ padding: 0;
}
table {
border-collapse: collapse;
}
+.page-content {
+ overflow: hidden;
+}
+
// Prevent code block overflow on export
pre {
padding-left: 12px;
font-size: 12px;
}
-.faded-small {
- display: none;
-}
-
.page-content {
margin: 0 auto;
}
@import "reset";
@import "variables";
@import "mixins";
+@import "spacing";
@import "html";
@import "text";
-@import "grid";
+@import "colors";
+@import "layout";
@import "blocks";
@import "buttons";
@import "tables";
}
}
-
-// Search results
-.search-results > h3 a {
- font-size: 0.66em;
- color: $primary;
- padding-left: $-m;
- i {
- padding-right: $-s;
- }
-}
-
// Back to top link
$btt-size: 40px;
[back-to-top] {
overflow-y: scroll;
height: 400px;
background-color: #EEEEEE;
+ margin-right: 0;
+ margin-left: 0;
+ }
+ .entity-list-item {
+ background-color: #FFF;
+ }
+ .entity-list-item p {
+ margin-bottom: 0;
+ }
+ .entity-list-item.selected {
+ background-color: rgba(0, 0, 0, 0.15) !important;
}
.loading {
height: 400px;
padding-top: $-l;
}
- .entity-list > p {
- text-align: center;
- padding-top: $-l;
- font-size: 1.333em;
- }
- .entity-list > div {
- padding-left: $-m;
- padding-right: $-m;
- background-color: #FFF;
- transition: all ease-in-out 120ms;
- cursor: pointer;
+ .entity-selector-add button {
+ margin: 0;
+ display: block;
+ width: 100%;
+ border: 0;
+ border-top: 1px solid #DDD;
}
&.compact {
font-size: 10px;
}
}
-.entity-list-item.selected {
- h3, i, p ,a, span {
- color: #EEE;
- }
-}
-
.scroll-box {
max-height: 250px;
overflow-y: scroll;
height:100%;
z-index: 150;
}
+
+.list-sort-container {
+ display: inline-block;
+ form {
+ display: inline-block;
+ }
+ .list-sort {
+ display: inline-grid;
+ margin-left: $-s;
+ grid-template-columns: 120px 40px;
+ border: 2px solid #DDD;
+ border-radius: 4px;
+ }
+ .list-sort-label {
+ font-weight: bold;
+ display: inline-block;
+ color: #888;
+ }
+ .list-sort-type {
+ text-align: left;
+ }
+ .list-sort-type, .list-sort-dir {
+ padding: $-xs $-s;
+ cursor: pointer;
+ }
+ .list-sort-dir {
+ border-left: 2px solid #DDD;
+ fill: #888;
+ .svg-icon {
+ transition: transform ease-in-out 120ms;
+ }
+ &:hover .svg-icon {
+ transform: rotate(180deg);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Activity text strings.
+ * Is used for all the text within activity logs & notifications.
+ */
+return [
+
+ // Pages
+ 'page_create' => 'vytvořená stránka',
+ 'page_create_notification' => 'Stránka byla úspěšně vytvořena',
+ 'page_update' => 'aktualizovaná stránka',
+ 'page_update_notification' => 'Stránka byla úspěšně aktualizována',
+ 'page_delete' => 'smazaná stránka',
+ 'page_delete_notification' => 'Stránka byla úspěšně smazána',
+ 'page_restore' => 'renovovaná stránka',
+ 'page_restore_notification' => 'Stránka byla úspěšně renovována',
+ 'page_move' => 'přesunutá stránka',
+
+ // Chapters
+ 'chapter_create' => 'vytvořená kapitola',
+ 'chapter_create_notification' => 'Kapitola byla úspěšně vytvořena',
+ 'chapter_update' => 'aktualizovaná kapitola',
+ 'chapter_update_notification' => 'Kapitola byla úspěšně aktualizována',
+ 'chapter_delete' => 'smazaná kapitola',
+ 'chapter_delete_notification' => 'Kapitola byla úspěšně smazána',
+ 'chapter_move' => 'přesunutá kapitola',
+
+ // Books
+ 'book_create' => 'vytvořená kniha',
+ 'book_create_notification' => 'Kniha byla úspěšně vytvořena',
+ 'book_update' => 'aktualizovaná kniha',
+ 'book_update_notification' => 'Kniha byla úspěšně aktualizována',
+ 'book_delete' => 'smazaná kniha',
+ 'book_delete_notification' => 'Kniha byla úspěšně smazána',
+ 'book_sort' => 'seřazená kniha',
+ 'book_sort_notification' => 'Kniha byla úspěšně seřazena',
+
+ // Bookshelves
+ 'bookshelf_create' => 'vytvořená knihovna',
+ 'bookshelf_create_notification' => 'Knihovna úspěšně vytvořena',
+ 'bookshelf_update' => 'aktualizovaná knihovna',
+ 'bookshelf_update_notification' => 'Knihovna byla úspěšně aktualizována',
+ 'bookshelf_delete' => 'smazaná knihovna',
+ 'bookshelf_delete_notification' => 'Knihovna byla úspěšně smazána',
+
+ // Other
+ 'commented_on' => 'okomentováno v',
+];
--- /dev/null
+<?php
+/**
+ * Authentication Language Lines
+ * The following language lines are used during authentication for various
+ * messages that we need to display to the user.
+ */
+return [
+
+ 'failed' => 'Neplatné přihlašovací údaje.',
+ 'throttle' => 'Příliš pokusů o přihlášení. Zkuste to prosím znovu za :seconds sekund.',
+
+ // Login & Register
+ 'sign_up' => 'Registrace',
+ 'log_in' => 'Přihlášení',
+ 'log_in_with' => 'Přihlásit přes :socialDriver',
+ 'sign_up_with' => 'Registrovat se přes :socialDriver',
+ 'logout' => 'Odhlásit',
+
+ 'name' => 'Jméno',
+ 'username' => 'Jméno účtu',
+ 'email' => 'Email',
+ 'password' => 'Heslo',
+ 'password_confirm' => 'Potvrdit heslo',
+ 'password_hint' => 'Musí mít víc než 5 znaků',
+ 'forgot_password' => 'Zapomněli jste heslo?',
+ 'remember_me' => 'Neodhlašovat',
+ 'ldap_email_hint' => 'Zadejte email, který chcete přiřadit k tomuto účtu.',
+ 'create_account' => 'Vytvořit účet',
+ 'social_login' => 'Přihlášení přes sociální sítě',
+ 'social_registration' => 'Registrace přes sociální sítě',
+ 'social_registration_text' => 'Registrovat a přihlásit se přes jinou službu',
+
+ 'register_thanks' => 'Díky za registraci!',
+ 'register_confirm' => 'Zkontrolujte prosím váš email a klikněte na potvrzovací tlačítko pro dokončení registrace do :appName.',
+ 'registrations_disabled' => 'Registrace jsou momentálně pozastaveny',
+ 'registration_email_domain_invalid' => 'Registrace z této emailové domény nejsou povoleny.',
+ 'register_success' => 'Díky za registraci! Jste registrovaní a přihlášení.',
+
+
+ // Password Reset
+ 'reset_password' => 'Resetovat heslo',
+ 'reset_password_send_instructions' => 'Zadejte vaší emailovou adresu a bude vám zaslán odkaz na resetování hesla.',
+ 'reset_password_send_button' => 'Poslat odkaz pro reset hesla',
+ 'reset_password_sent_success' => 'Odkaz na resetování hesla vám byl zaslán na :email.',
+ 'reset_password_success' => 'Vaše heslo bylo úspěšně resetováno.',
+ 'email_reset_subject' => 'Reset hesla do :appName',
+ 'email_reset_text' => 'Tento email jste obdrželi, protože jsme dostali žádost o resetování vašeho hesla k účtu v :appName.',
+ 'email_reset_not_requested' => 'Pokud jste o reset vašeho hesla nežádali, prostě tento dopis smažte a je to.',
+
+
+ // Email Confirmation
+ 'email_confirm_subject' => 'Potvrďte vaši emailovou adresu pro :appName',
+ 'email_confirm_greeting' => 'Díky že jste se přidali do :appName!',
+ 'email_confirm_text' => 'Prosíme potvrďte funkčnost vaší emailové adresy kliknutím na tlačítko níže:',
+ 'email_confirm_action' => 'Potvrdit emailovou adresu',
+ 'email_confirm_send_error' => 'Potvrzení emailové adresy je vyžadováno, ale systém vám nedokázal odeslat email. Kontaktujte správce aby to dal do kupy a potvrzovací email vám dorazil.',
+ 'email_confirm_success' => 'Vaše emailová adresa byla potvrzena!',
+ 'email_confirm_resent' => 'Email s žádostí o potvrzení vaší emailové adresy byl odeslán. Podívejte se do příchozí pošty.',
+
+ 'email_not_confirmed' => 'Emailová adresa nebyla potvrzena',
+ 'email_not_confirmed_text' => 'Vaše emailová adresa nebyla dosud potvrzena.',
+ 'email_not_confirmed_click_link' => 'Klikněte na odkaz v emailu který jsme vám zaslali ihned po registraci.',
+ 'email_not_confirmed_resend' => 'Pokud nemůžete nalézt email v příchozí poště, můžete si jej nechat poslat znovu pomocí formuláře níže.',
+ 'email_not_confirmed_resend_button' => 'Znovu poslat email pro potvrzení emailové adresy',
+];
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Common elements found throughout many areas of BookStack.
+ */
+return [
+
+ // Buttons
+ 'cancel' => 'Storno',
+ 'confirm' => 'Potvrdit',
+ 'back' => 'Zpět',
+ 'save' => 'Uložit',
+ 'continue' => 'Pokračovat',
+ 'select' => 'Zvolit',
+ 'more' => 'Více',
+
+ // Form Labels
+ 'name' => 'Jméno',
+ 'description' => 'Popis',
+ 'role' => 'Role',
+ 'cover_image' => 'Obrázek na přebal',
+ 'cover_image_description' => 'Obrázek by měl být asi 440 × 250px.',
+
+ // Actions
+ 'actions' => 'Akce',
+ 'view' => 'Pohled',
+ 'create' => 'Vytvořit',
+ 'update' => 'Aktualizovat',
+ 'edit' => 'Upravit',
+ 'sort' => 'Řadit',
+ 'move' => 'Přesunout',
+ 'copy' => 'Kopírovat',
+ 'reply' => 'Odpovědět',
+ 'delete' => 'Smazat',
+ 'search' => 'Hledat',
+ 'search_clear' => 'Vyčistit hledání',
+ 'reset' => 'Reset',
+ 'remove' => 'Odstranit',
+ 'add' => 'Přidat',
+
+ // Misc
+ 'deleted_user' => 'Smazaný uživatel',
+ 'no_activity' => 'Žádná aktivita k zobrazení',
+ 'no_items' => 'Žádné položky nejsou k mání',
+ 'back_to_top' => 'Zpět na začátek',
+ 'toggle_details' => 'Ukázat detaily',
+ 'toggle_thumbnails' => 'Ukázat náhledy',
+ 'details' => 'Detaily',
+ 'grid_view' => 'Zobrazit dlaždice',
+ 'list_view' => 'Zobrazit seznam',
+ 'default' => 'Výchozí',
+
+ // Header
+ 'view_profile' => 'Ukázat profil',
+ 'edit_profile' => 'Upravit profil',
+
+ // Email Content
+ 'email_action_help' => 'Pokud se vám nedaří kliknout na tlačítko ":actionText", zkopírujte odkaz níže přímo do webového prohlížeče:',
+ 'email_rights' => 'Všechna práva vyhrazena',
+];
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Text used in custom JavaScript driven components.
+ */
+return [
+
+ // Image Manager
+ 'image_select' => 'Volba obrázku',
+ 'image_all' => 'Vše',
+ 'image_all_title' => 'Zobrazit všechny obrázky',
+ 'image_book_title' => 'Zobrazit obrázky nahrané k této knize',
+ 'image_page_title' => 'Zobrazit obrázky nahrané k této stránce',
+ 'image_search_hint' => 'Hledat podle názvu obrázku',
+ 'image_uploaded' => 'Nahráno :uploadedDate',
+ 'image_load_more' => 'Načíst další',
+ 'image_image_name' => 'Název obrázku',
+ 'image_delete_used' => 'Tento obrázek je použit v následujících stránkách.',
+ 'image_delete_confirm' => 'Stisknětě smazat ještě jednou pro potvrzení smazání tohoto obrázku.',
+ 'image_select_image' => 'Zvolte obrázek',
+ 'image_dropzone' => 'Přetáhněte sem obrázky myší nebo sem klikněte pro vybrání souboru.',
+ 'images_deleted' => 'Obrázky smazány',
+ 'image_preview' => 'Náhled obrázku',
+ 'image_upload_success' => 'Obrázek byl úspěšně nahrán',
+ 'image_update_success' => 'Podrobnosti o obrázku byly úspěšně aktualizovány',
+ 'image_delete_success' => 'Obrázek byl úspěšně smazán',
+ 'image_upload_remove' => 'Odstranit',
+
+ // Code Editor
+ 'code_editor' => 'Upravit kód',
+ 'code_language' => 'Jazyk kódu',
+ 'code_content' => 'Obsah kódu',
+ 'code_save' => 'Uložit kód',
+];
--- /dev/null
+<?php
+/**
+ * Text used for 'Entities' (Document Structure Elements) such as
+ * Books, Shelves, Chapters & Pages
+ */
+return [
+
+ // Shared
+ 'recently_created' => 'Nedávno vytvořené',
+ 'recently_created_pages' => 'Nedávno vytvořené stránky',
+ 'recently_updated_pages' => 'Nedávno aktualizované stránky',
+ 'recently_created_chapters' => 'Nedávno vytvořené kapitoly',
+ 'recently_created_books' => 'Nedávno vytvořené knihy',
+ 'recently_update' => 'Nedávno aktualizované',
+ 'recently_viewed' => 'Nedávno prohlížené',
+ 'recent_activity' => 'Nedávné činnosti',
+ 'create_now' => 'Vytvořte jí',
+ 'revisions' => 'Revize',
+ 'meta_revision' => 'Revize #:revisionCount',
+ 'meta_created' => 'Vytvořeno :timeLength',
+ 'meta_created_name' => 'Vytvořeno :timeLength uživatelem :user',
+ 'meta_updated' => 'Aktualizováno :timeLength',
+ 'meta_updated_name' => 'Aktualizováno :timeLength uživatelem :user',
+ 'entity_select' => 'Volba prvku',
+ 'images' => 'Obrázky',
+ 'my_recent_drafts' => 'Mé nedávné koncepty',
+ 'my_recently_viewed' => 'Naposledy navštívené',
+ 'no_pages_viewed' => 'Zatím jste nic neshlédli',
+ 'no_pages_recently_created' => 'Zatím nebyly vytvořeny žádné stránky',
+ 'no_pages_recently_updated' => 'Zatím nebyly aktualizovány žádné stránky',
+ 'export' => 'Export',
+ 'export_html' => 'Všeobjímající HTML',
+ 'export_pdf' => 'PDF dokument',
+ 'export_text' => 'Čistý text (txt)',
+
+ // Permissions and restrictions
+ 'permissions' => 'Práva',
+ 'permissions_intro' => 'Zaškrtnutím překryjete práva v uživatelských rolích nastavením níže.',
+ 'permissions_enable' => 'Zapnout vlastní práva',
+ 'permissions_save' => 'Uložit práva',
+
+ // Search
+ 'search_results' => 'Výsledky hledání',
+ 'search_total_results_found' => 'Nalezen :count výsledek|Nalezeny :count výsledky|Nalezeny :count výsledky|Nalezeny :count výsledky|Nalezeno :count výsledků',
+ 'search_clear' => 'Vyčistit hledání',
+ 'search_no_pages' => 'Žádná stránka neodpovídá hledanému výrazu',
+ 'search_for_term' => 'Hledat :term',
+ 'search_more' => 'Další výsledky',
+ 'search_filters' => 'Filtry hledání',
+ 'search_content_type' => 'Typ obsahu',
+ 'search_exact_matches' => 'Musí obsahovat',
+ 'search_tags' => 'Hledat štítky (tagy)',
+ 'search_options' => 'Volby',
+ 'search_viewed_by_me' => 'Shlédnuto mnou',
+ 'search_not_viewed_by_me' => 'Neshlédnuto mnou',
+ 'search_permissions_set' => 'Sada práv',
+ 'search_created_by_me' => 'Vytvořeno mnou',
+ 'search_updated_by_me' => 'Aktualizováno',
+ 'search_date_options' => 'Volby datumu',
+ 'search_updated_before' => 'Aktualizováno před',
+ 'search_updated_after' => 'Aktualizováno po',
+ 'search_created_before' => 'Vytvořeno před',
+ 'search_created_after' => 'Vytvořeno po',
+ 'search_set_date' => 'Datum',
+ 'search_update' => 'Hledat znovu',
+
+ // Shelves
+ 'shelf' => 'Knihovna',
+ 'shelves' => 'Knihovny',
+ 'shelves_long' => 'Knihovny',
+ 'shelves_empty' => 'Žádné knihovny nebyly vytvořeny',
+ 'shelves_create' => 'Vytvořit novou knihovnu',
+ 'shelves_popular' => 'Populární knihovny',
+ 'shelves_new' => 'Nové knihovny',
+ 'shelves_popular_empty' => 'Nejpopulárnější knihovny se objeví zde.',
+ 'shelves_new_empty' => 'Nejnovější knihovny se objeví zde.',
+ 'shelves_save' => 'Uložit knihovnu',
+ 'shelves_books' => 'Knihy v této knihovně',
+ 'shelves_add_books' => 'Přidat knihy do knihovny',
+ 'shelves_drag_books' => 'Knihu přidáte jejím přetažením sem.',
+ 'shelves_empty_contents' => 'Tato knihovna neobsahuje žádné knihy',
+ 'shelves_edit_and_assign' => 'Pro přidáni knih do knihovny stiskněte úprvy.',
+ 'shelves_edit_named' => 'Upravit knihovnu :name',
+ 'shelves_edit' => 'Upravit knihovnu',
+ 'shelves_delete' => 'Smazat knihovnu',
+ 'shelves_delete_named' => 'Smazat knihovnu :name',
+ 'shelves_delete_explain' => "Chystáte se smazat knihovnu ':name'. Knihy v ní obsažené zůstanou zachovány.",
+ 'shelves_delete_confirmation' => 'Opravdu chcete smazat tuto knihovnu?',
+ 'shelves_permissions' => 'Práva knihovny',
+ 'shelves_permissions_updated' => 'Práva knihovny byla aktualizována',
+ 'shelves_permissions_active' => 'Účinná práva knihovny',
+ 'shelves_copy_permissions_to_books' => 'Přenést práva na knihy',
+ 'shelves_copy_permissions' => 'Zkopírovat práva',
+ 'shelves_copy_permissions_explain' => 'Práva knihovny budou aplikována na všechny knihy v ní obsažené. Před použitím se ujistěte, že jste uložili změny práv knihovny.',
+ 'shelves_copy_permission_success' => 'Práva knihovny přenesena na knihy (celkem :count)',
+
+ // Books
+ 'book' => 'Kniha',
+ 'books' => 'Knihy',
+ 'x_books' => ':count Kniha|:count Knihy|:count Knihy|:count Knihy|:count Knih',
+ 'books_empty' => 'Žádné knihy nebyly vytvořeny',
+ 'books_popular' => 'Populární knihy',
+ 'books_recent' => 'Nedávné knihy',
+ 'books_new' => 'Nové knihy',
+ 'books_popular_empty' => 'Zde budou zobrazeny nejpopulárnější knihy.',
+ 'books_new_empty' => 'Zde budou zobrazeny nově vytvořené knihy.',
+ 'books_create' => 'Vytvořit novou knihu',
+ 'books_delete' => 'Smazat knihu',
+ 'books_delete_named' => 'Smazat knihu :bookName',
+ 'books_delete_explain' => 'Kniha \':bookName\' bude smazána. Všechny její stránky a kapitoly budou taktéž smazány.',
+ 'books_delete_confirmation' => 'Opravdu chcete tuto knihu smazat.',
+ 'books_edit' => 'Upravit knihu',
+ 'books_edit_named' => 'Upravit knihu :bookName',
+ 'books_form_book_name' => 'Název knihy',
+ 'books_save' => 'Uložit knihu',
+ 'books_permissions' => 'Práva knihy',
+ 'books_permissions_updated' => 'Práva knihy upravena',
+ 'books_empty_contents' => 'V této knize nebyly vytvořeny žádné stránky ani kapitoly.',
+ 'books_empty_create_page' => 'Vytvořit novou stránku',
+ 'books_empty_or' => 'nebo',
+ 'books_empty_sort_current_book' => 'Seřadit tuto knihu',
+ 'books_empty_add_chapter' => 'Přidat kapitolu',
+ 'books_permissions_active' => 'Účinná práva knihy',
+ 'books_search_this' => 'Prohledat tuto knihu',
+ 'books_navigation' => 'Obsah knihy',
+ 'books_sort' => 'Seřadit obsah knihy',
+ 'books_sort_named' => 'Seřadit knihu :bookName',
+ 'books_sort_show_other' => 'Ukázat ostatní knihy',
+ 'books_sort_save' => 'Uložit nové pořadí',
+
+ // Chapters
+ 'chapter' => 'Kapitola',
+ 'chapters' => 'Kapitoly',
+ 'x_chapters' => ':count kapitola|:count kapitoly|:count kapitoly|:count kapitoly|:count kapitol',
+ 'chapters_popular' => 'Populární kapitoly',
+ 'chapters_new' => 'Nová kapitola',
+ 'chapters_create' => 'Vytvořit novou kapitolu',
+ 'chapters_delete' => 'Smazat kapitolu',
+ 'chapters_delete_named' => 'Smazat kapitolu :chapterName',
+ 'chapters_delete_explain' => 'Kapitola \':chapterName\' bude smazána. Všechny stránky v ní obsažené budou přesunuty přímo pod samotnou knihu.',
+ 'chapters_delete_confirm' => 'Opravdu chcete tuto kapitolu smazat?',
+ 'chapters_edit' => 'Upravit kapitolu',
+ 'chapters_edit_named' => 'Upravit kapitolu :chapterName',
+ 'chapters_save' => 'Uložit kapitolu',
+ 'chapters_move' => 'Přesunout kapitolu',
+ 'chapters_move_named' => 'Přesunout kapitolu :chapterName',
+ 'chapter_move_success' => 'Kapitola přesunuta do knihy :bookName',
+ 'chapters_permissions' => 'Práva kapitoly',
+ 'chapters_empty' => 'Tato kapitola neobsahuje žádné stránky',
+ 'chapters_permissions_active' => 'Účinná práva kapitoly',
+ 'chapters_permissions_success' => 'Práva kapitoly aktualizována',
+ 'chapters_search_this' => 'Prohledat tuto kapitolu',
+
+ // Pages
+ 'page' => 'Stránka',
+ 'pages' => 'Stránky',
+ 'x_pages' => ':count strana|:count strany|:count strany|:count strany|:count stran',
+ 'pages_popular' => 'Populární stránky',
+ 'pages_new' => 'Nová stránka',
+ 'pages_attachments' => 'Přílohy',
+ 'pages_navigation' => 'Obsah stránky',
+ 'pages_delete' => 'Smazat stránku',
+ 'pages_delete_named' => 'Smazat stránku :pageName',
+ 'pages_delete_draft_named' => 'Smazat koncept stránky :pageName',
+ 'pages_delete_draft' => 'Smazat koncept stránky',
+ 'pages_delete_success' => 'Stránka smazána',
+ 'pages_delete_draft_success' => 'Koncept stránky smazán',
+ 'pages_delete_confirm' => 'Opravdu chcete tuto stránku smazat?',
+ 'pages_delete_draft_confirm' => 'Opravdu chcete tento koncept stránky smazat?',
+ 'pages_editing_named' => 'Úpravy stránky :pageName',
+ 'pages_edit_toggle_header' => 'Ukázat hlavičku',
+ 'pages_edit_save_draft' => 'Uložit koncept',
+ 'pages_edit_draft' => 'Upravit koncept stránky',
+ 'pages_editing_draft' => 'Úpravy konceptu',
+ 'pages_editing_page' => 'Úpravy stránky',
+ 'pages_edit_draft_save_at' => 'Koncept uložen v ',
+ 'pages_edit_delete_draft' => 'Smazat koncept',
+ 'pages_edit_discard_draft' => 'Zahodit koncept',
+ 'pages_edit_set_changelog' => 'Zadat komentář ke změnám',
+ 'pages_edit_enter_changelog_desc' => 'Zadejte stručný popis změn, které jste provedli.',
+ 'pages_edit_enter_changelog' => 'Vložit komentáře ke změnám',
+ 'pages_save' => 'Uložit stránku',
+ 'pages_title' => 'Nadpis stránky',
+ 'pages_name' => 'Název stránky',
+ 'pages_md_editor' => 'Editor',
+ 'pages_md_preview' => 'Náhled',
+ 'pages_md_insert_image' => 'Vložit obrázek',
+ 'pages_md_insert_link' => 'Vložit odkaz na prvek',
+ 'pages_md_insert_drawing' => 'Vložit kresbu',
+ 'pages_not_in_chapter' => 'Stránka není součástí žádné kapitoly',
+ 'pages_move' => 'Přesunout stránku',
+ 'pages_move_success' => 'Stránka přesunuta do ":parentName"',
+ 'pages_copy' => 'Kopírovat stránku',
+ 'pages_copy_desination' => 'Cíl kopírování',
+ 'pages_copy_success' => 'Stránka byla úspěšně zkopírována',
+ 'pages_permissions' => 'Práva stránky',
+ 'pages_permissions_success' => 'Práva stránky aktualizována',
+ 'pages_revision' => 'Revize',
+ 'pages_revisions' => 'Revize stránky',
+ 'pages_revisions_named' => 'Revize stránky :pageName',
+ 'pages_revision_named' => 'Revize stránky :pageName',
+ 'pages_revisions_created_by' => 'Vytvořeno uživatelem',
+ 'pages_revisions_date' => 'Datum revize',
+ 'pages_revisions_number' => '#',
+ 'pages_revisions_changelog' => 'Komentáře změn',
+ 'pages_revisions_changes' => 'Změny',
+ 'pages_revisions_current' => 'Aktuální verze',
+ 'pages_revisions_preview' => 'Náhled',
+ 'pages_revisions_restore' => 'Renovovat',
+ 'pages_revisions_none' => 'Tato stránka nemá žádné revize',
+ 'pages_copy_link' => 'Zkopírovat odkaz',
+ 'pages_edit_content_link' => 'Upravit obsah',
+ 'pages_permissions_active' => 'Účinná práva stránky',
+ 'pages_initial_revision' => 'První vydání',
+ 'pages_initial_name' => 'Nová stránka',
+ 'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen před :timeDiff.',
+ 'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
+ 'pages_draft_edit_active' => [
+ 'start_a' => 'Uživatelé začali upravovat tuto stránku (celkem :count)',
+ 'start_b' => 'Uživatel :userName začal upravovat tuto stránku',
+ 'time_a' => 'od doby, kdy byla tato stránky naposledy aktualizována',
+ 'time_b' => 'v posledních minutách (:minCount min.)',
+ 'message' => ':start :time. Dávejte pozor abyste nepřepsali změny ostatním!',
+ ],
+ 'pages_draft_discarded' => 'Koncept zahozen. Editor nyní obsahuje aktuální verzi stránky.',
+ 'pages_specific' => 'Konkrétní stránka',
+
+ // Editor Sidebar
+ 'page_tags' => 'Štítky stránky',
+ 'chapter_tags' => 'Štítky kapitoly',
+ 'book_tags' => 'Štítky knihy',
+ 'shelf_tags' => 'Štítky knihovny',
+ 'tag' => 'Štítek',
+ 'tags' => 'Štítky',
+ 'tag_value' => 'Hodnota Štítku (volitelné)',
+ 'tags_explain' => "Přidejte si štítky pro lepší kategorizaci knih. \n Štítky mohou nést i hodnotu pro detailnější klasifikaci.",
+ 'tags_add' => 'Přidat další štítek',
+ 'attachments' => 'Přílohy',
+ 'attachments_explain' => 'Nahrajte soubory nebo připojte odkazy, které se zobrazí na stránce. Budou k nalezení v postranní liště.',
+ 'attachments_explain_instant_save' => 'Změny zde provedené se okamžitě ukládají.',
+ 'attachments_items' => 'Připojené položky',
+ 'attachments_upload' => 'Nahrát soubor',
+ 'attachments_link' => 'Připojit odkaz',
+ 'attachments_set_link' => 'Nastavit odkaz',
+ 'attachments_delete_confirm' => 'Stiskněte smazat znovu pro potvrzení smazání.',
+ 'attachments_dropzone' => 'Přetáhněte sem soubory myší nebo sem kliknětě pro vybrání souboru.',
+ 'attachments_no_files' => 'Žádné soubory nebyli nahrány',
+ 'attachments_explain_link' => 'Můžete pouze připojit odkaz pokud nechcete nahrávat soubor přímo. Může to být odkaz na jinou stránku nebo na soubor v cloudu.',
+ 'attachments_link_name' => 'Název odkazu',
+ 'attachment_link' => 'Odkaz na přílohu',
+ 'attachments_link_url' => 'Odkaz na soubor',
+ 'attachments_link_url_hint' => 'URL stránky nebo souboru',
+ 'attach' => 'Připojit',
+ 'attachments_edit_file' => 'Upravit soubor',
+ 'attachments_edit_file_name' => 'Název souboru',
+ 'attachments_edit_drop_upload' => 'Přetáhněte sem soubor myší nebo klikněte pro nahrání nového a následné přepsání starého.',
+ 'attachments_order_updated' => 'Pořadí příloh aktualizováno',
+ 'attachments_updated_success' => 'Podrobnosti příloh aktualizovány',
+ 'attachments_deleted' => 'Příloha byla smazána',
+ 'attachments_file_uploaded' => 'Soubor byl úspěšně nahrán',
+ 'attachments_file_updated' => 'Soubor byl úspěšně aktualizován',
+ 'attachments_link_attached' => 'Odkaz úspěšně přiložen ke stránce',
+
+ // Profile View
+ 'profile_user_for_x' => 'Uživatelem již :time',
+ 'profile_created_content' => 'Vytvořený obsah',
+ 'profile_not_created_pages' => ':userName nevytvořil/a žádný obsah',
+ 'profile_not_created_chapters' => ':userName nevytvořil/a žádné kapitoly',
+ 'profile_not_created_books' => ':userName nevytvořil/a žádné knihy',
+
+ // Comments
+ 'comment' => 'Komentář',
+ 'comments' => 'Komentáře',
+ 'comment_add' => 'Přidat komentář',
+ 'comment_placeholder' => 'Zanechat komentář zde',
+ 'comment_count' => '{0} Bez komentářů|{1} 1 komentář|[2,4] :count komentáře|[5,*] :count komentářů',
+ 'comment_save' => 'Uložit komentář',
+ 'comment_saving' => 'Ukládání komentáře...',
+ 'comment_deleting' => 'Mazání komentáře...',
+ 'comment_new' => 'Nový komentář',
+ 'comment_created' => 'komentováno :createDiff',
+ 'comment_updated' => 'Aktualizováno :updateDiff uživatelem :username',
+ 'comment_deleted_success' => 'Komentář smazán',
+ 'comment_created_success' => 'Komentář přidán',
+ 'comment_updated_success' => 'Komentář aktualizován',
+ 'comment_delete_confirm' => 'Opravdu chcete smazat tento komentář?',
+ 'comment_in_reply_to' => 'Odpověď na :commentId',
+
+ // Revision
+ 'revision_delete_confirm' => 'Opravdu chcete smazat tuto revizi?',
+ 'revision_delete_success' => 'Revize smazána',
+ 'revision_cannot_delete_latest' => 'Nelze smazat poslední revizi.'
+
+];
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Text shown in error messaging.
+ */
+return [
+
+ // Permissions
+ 'permission' => 'Nemáte povolení přistupovat na dotazovanou stránku.',
+ 'permissionJson' => 'Nemáte povolení k provedení požadované akce.',
+
+ // Auth
+ 'error_user_exists_different_creds' => 'Uživatel s emailem :email již existuje ale s jinými přihlašovacími údaji.',
+ 'email_already_confirmed' => 'Emailová adresa již byla potvrzena. Zkuste se přihlásit.',
+ 'email_confirmation_invalid' => 'Tento potvrzovací odkaz již neplatí nebo už byl použit. Zkuste prosím registraci znovu.',
+ 'email_confirmation_expired' => 'Potvrzovací odkaz už neplatí, email s novým odkazem už byl poslán.',
+ 'ldap_fail_anonymous' => 'Přístup k adresáři LDAP jako anonymní uživatel (anonymous bind) selhal',
+ 'ldap_fail_authed' => 'Přístup k adresáři LDAP pomocí zadaného jména (dn) a hesla selhal',
+ 'ldap_extension_not_installed' => 'Není nainstalováno rozšíření LDAP pro PHP',
+ 'ldap_cannot_connect' => 'Nelze se připojit k adresáři LDAP. Prvotní připojení selhalo.',
+ 'social_no_action_defined' => 'Nebyla zvolena žádá akce',
+ 'social_login_bad_response' => "Nastala chyba během přihlašování přes :socialAccount \n:error",
+ 'social_account_in_use' => 'Tento účet na :socialAccount se již používá. Pokuste se s ním přihlásit volbou Přihlásit přes :socialAccount.',
+ 'social_account_email_in_use' => 'Emailová adresa :email se již používá. Pokud máte již máte náš účet, můžete si jej propojit se svým účtem na :socialAccount v nastavení vašeho profilu.',
+ 'social_account_existing' => 'Tento účet na :socialAccount je již propojen s vaším profilem zde.',
+ 'social_account_already_used_existing' => 'Tento účet na :socialAccount je již používán jiným uživatelem.',
+ 'social_account_not_used' => 'Tento účet na :socialAccount není spřažen s žádným uživatelem. Prosím přiřaďtě si jej v nastavení svého profilu.',
+ 'social_account_register_instructions' => 'Pokud ještě nemáte náš účet, můžete se zaregistrovat pomocí vašeho účtu na :socialAccount.',
+ 'social_driver_not_found' => 'Doplněk pro tohoto správce identity nebyl nalezen.',
+ 'social_driver_not_configured' => 'Nastavení vašeho účtu na :socialAccount není správné. :socialAccount musí mít vaše svolení pro naší aplikaci vás přihlásit.',
+
+ // System
+ 'path_not_writable' => 'Nelze zapisovat na cestu k souboru :filePath. Zajistěte aby se dalo nahrávat na server.',
+ 'cannot_get_image_from_url' => 'Nelze získat obrázek z adresy :url',
+ 'cannot_create_thumbs' => 'Server nedokáže udělat náhledy. Zkontrolujte, že rozšíření GD pro PHP je nainstalováno.',
+ 'server_upload_limit' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.',
+ 'uploaded' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', //TODO to je nějaký podezřelý
+ 'image_upload_error' => 'Nastala chyba během nahrávání souboru',
+ 'image_upload_type_error' => 'Typ nahrávaného obrázku je neplatný.',
+ 'file_upload_timeout' => 'Nahrávání souboru trvalo příliš dlouho a tak bylo ukončeno.',
+
+ // Attachments
+ 'attachment_page_mismatch' => 'Došlo ke zmatení stránky během nahrávání přílohy.',
+ 'attachment_not_found' => 'Příloha nenalezena',
+
+ // Pages
+ 'page_draft_autosave_fail' => 'Nepovedlo se uložit koncept. Než stránku uložíte, ujistěte se, že jste připojeni k internetu.',
+ 'page_custom_home_deletion' => 'Nelze smazat tuto stránku, protože je nastavena jako uvítací stránka.',
+
+ // Entities
+ 'entity_not_found' => 'Prvek nenalezen',
+ 'bookshelf_not_found' => 'Knihovna nenalezena',
+ 'book_not_found' => 'Kniha nenalezena',
+ 'page_not_found' => 'Stránka nenalezena',
+ 'chapter_not_found' => 'Kapitola nenalezena',
+ 'selected_book_not_found' => 'Vybraná kniha nebyla nalezena',
+ 'selected_book_chapter_not_found' => 'Zvolená kniha nebo kapitola nebyla nalezena',
+ 'guests_cannot_save_drafts' => 'Návštěvníci z řad veřejnosti nemohou ukládat koncepty.',
+
+ // Users
+ 'users_cannot_delete_only_admin' => 'Nemůžete smazat posledního administrátora',
+ 'users_cannot_delete_guest' => 'Uživatele host není možno smazat',
+
+ // Roles
+ 'role_cannot_be_edited' => 'Tuto roli nelze editovat',
+ 'role_system_cannot_be_deleted' => 'Toto je systémová role a nelze jí smazat.',
+ 'role_registration_default_cannot_delete' => 'Tuto roli nelze smazat dokud je nastavená jako výchozí role pro registraci nových uživatelů.',
+ 'role_cannot_remove_only_admin' => 'Tento uživatel má roli administrátora. Přiřaďte roli administrátora někomu jinému než jí odeberete zde.',
+
+ // Comments
+ 'comment_list' => 'Při dotahování komentářů nastala chyba.',
+ 'cannot_add_comment_to_draft' => 'Nemůžete přidávat komentáře ke konceptu.',
+ 'comment_add' => 'Při přidávání / aktualizaci komentáře nastala chyba.',
+ 'comment_delete' => 'Při mazání komentáře nastala chyba.',
+ 'empty_comment' => 'Nemůžete přidat prázdný komentář.', //This has a deep thinking value
+
+ // Error pages
+ '404_page_not_found' => 'Stránka nenalezena',
+ 'sorry_page_not_found' => 'Omlouváme se, ale stránka, kterou hledáte nebyla nalezena.',
+ 'return_home' => 'Návrat domů',
+ 'error_occurred' => 'Nastala chyba',
+ 'app_down' => ':appName je momentálně vypnutá',
+ 'back_soon' => 'Brzy naběhne.',
+
+];
--- /dev/null
+<?php
+/**
+ * Pagination Language Lines
+ * The following language lines are used by the paginator library to build
+ * the simple pagination links.
+ */
+return [
+
+ 'previous' => '« Pøedchozí',
+ 'next' => 'Dal\9aí »',
+
+];
--- /dev/null
+<?php
+/**
+ * Password Reminder Language Lines
+ * The following language lines are the default lines which match reasons
+ * that are given by the password broker for a password update attempt has failed.
+ */
+return [
+
+ 'password' => 'Heslo musí být alespoň 6 znaků dlouhé a shodovat se v obou polích.',
+ 'user' => "Nemůžeme najít uživatele se zadanou emailovou adresou.",
+ 'token' => 'Tento odkaz pro reset hesla je neplatný.',
+ 'sent' => 'Poslali jsme vám odkaz pro reset hesla!',
+ 'reset' => 'Vaše heslo bylo resetováno!',
+
+];
--- /dev/null
+<?php
+/**
+ * Settings text strings
+ * Contains all text strings used in the general settings sections of BookStack
+ * including users and roles.
+ */
+return [
+
+ // Common Messages
+ 'settings' => 'Nastavení',
+ 'settings_save' => 'Uložit nastavení',
+ 'settings_save_success' => 'Nastavení bylo uloženo',
+
+ // App Settings
+ 'app_settings' => 'Nastavení aplikace',
+ 'app_name' => 'Název aplikace',
+ 'app_name_desc' => 'Název se bude zobrazovat v záhlaví této aplikace a v odesílaných emailech.',
+ 'app_name_header' => 'Zobrazovát název aplikace v záhlaví?',
+ 'app_public_viewing' => 'Povolit prohlížení veřejností?',
+ 'app_secure_images' => 'Nahrávat obrázky neveřejně a zabezpečeně?',
+ 'app_secure_images_desc' => 'Z výkonnostních důvodů jsou všechny obrázky veřejné. Tato volba přidá do adresy obrázku náhodné číslo, aby nikdo neodhadnul adresu obrázku. Zajistěte ať adresáře nikomu nezobrazují seznam souborů.',
+ 'app_editor' => 'Editor stránek',
+ 'app_editor_desc' => 'Zvolte který editor budou užívat všichni uživatelé k úpravě stránek.',
+ 'app_custom_html' => 'Vlastní HTML kód pro sekci hlavičky (<head>).',
+ 'app_custom_html_desc' => 'Cokoliv sem napíšete bude přidáno na konec sekce <head> v každém místě této aplikace. To se hodí pro přidávání nebo změnu CSS stylů nebo přidání kódu pro analýzu používání (např.: google analytics.).',
+ 'app_logo' => 'Logo aplikace',
+ 'app_logo_desc' => 'Obrázek by měl mít 43 pixelů na výšku. <br>Větší obrázky zmenšíme na tuto velikost.',
+ 'app_primary_color' => 'Hlavní barva aplikace',
+ 'app_primary_color_desc' => 'Zápis by měl být hexa (#aabbcc). <br>Pro základní barvu nechte pole prázdné.',
+ 'app_homepage' => 'Úvodní stránka aplikace',
+ 'app_homepage_desc' => 'Zvolte pohled který se objeví jako úvodní stránka po přihlášení. Pokud zvolíte stránku, její specifická oprávnění budou ignorována (výjimka z výjimky 😜).',
+ 'app_homepage_select' => 'Zvolte stránku',
+ 'app_disable_comments' => 'Zakázání komentářů',
+ 'app_disable_comments_desc' => 'Zakáže komentáře napříč všemi stránkami. Existující komentáře se přestanou zobrazovat.',
+
+ // Registration Settings
+ 'reg_settings' => 'Nastavení registrace',
+ 'reg_allow' => 'Povolit registrace?',
+ 'reg_default_role' => 'Role přiřazená po registraci',
+ 'reg_confirm_email' => 'Vyžadovat ověření emailové adresy?',
+ 'reg_confirm_email_desc' => 'Pokud zapnete omezení emailové domény, tak bude ověřování emailové adresy vyžadováno vždy.',
+ 'reg_confirm_restrict_domain' => 'Omezit registraci podle domény',
+ 'reg_confirm_restrict_domain_desc' => 'Zadejte emailové domény, kterým bude povolena registrace uživatelů. Oddělujete čárkou. Uživatelům bude odeslán email s odkazem pro potvrzení vlastnictví emailové adresy. Bez potvrzení nebudou moci aplikaci používat. <br> Pozn.: Uživatelé si mohou emailovou adresu změnit po úspěšné registraci.',
+ 'reg_confirm_restrict_domain_placeholder' => 'Žádná omezení nebyla nastvena',
+
+ // Maintenance settings
+ 'maint' => 'Údržba',
+ 'maint_image_cleanup' => 'Pročistění obrázků',
+ 'maint_image_cleanup_desc' => "Prohledá stránky a jejich revize, aby zjistil, které obrázky a kresby jsou momentálně používány a které jsou zbytečné. Zajistěte plnou zálohu databáze a obrázků než se do toho pustíte.",
+ 'maint_image_cleanup_ignore_revisions' => 'Ignorovat obrázky v revizích',
+ 'maint_image_cleanup_run' => 'Spustit pročištění',
+ 'maint_image_cleanup_warning' => 'Nalezeno :count potenciálně nepoužitých obrázků. Jste si jistí, že je chcete smazat?',
+
+ 'maint_image_cleanup_success' => 'Potenciálně nepoužité obrázky byly smazány. Celkem :count.',
+ 'maint_image_cleanup_nothing_found' => 'Žádné potenciálně nepoužité obrázky nebyly nalezeny. Nic nebylo smazáno.',
+
+ // Role Settings
+ 'roles' => 'Role',
+ 'role_user_roles' => 'Uživatelské role',
+ 'role_create' => 'Vytvořit novou roli',
+ 'role_create_success' => 'Role byla úspěšně vytvořena',
+ 'role_delete' => 'Smazat roli',
+ 'role_delete_confirm' => 'Role \':roleName\' bude smazána.',
+ 'role_delete_users_assigned' => 'Role je přiřazena :userCount uživatelům. Pokud jim chcete náhradou přidělit jinou roli, zvolte jednu z následujících.',
+ 'role_delete_no_migration' => "Nepřiřazovat uživatelům náhradní roli",
+ 'role_delete_sure' => 'Opravdu chcete tuto roli smazat?',
+ 'role_delete_success' => 'Role byla úspěšně smazána',
+ 'role_edit' => 'Upravit roli',
+ 'role_details' => 'Detaily role',
+ 'role_name' => 'Název role',
+ 'role_desc' => 'Stručný popis role',
+ 'role_external_auth_id' => 'Přihlašovací identifikátory třetích stran',
+ 'role_system' => 'Systémová oprávnění',
+ 'role_manage_users' => 'Správa úživatelů',
+ 'role_manage_roles' => 'Správa rolí a jejich práv',
+ 'role_manage_entity_permissions' => 'Správa práv všech knih, kapitol a stránek',
+ 'role_manage_own_entity_permissions' => 'Správa práv vlastních knih, kapitol a stránek',
+ 'role_manage_settings' => 'Správa nastavení aplikace',
+ 'role_asset' => 'Práva děl',
+ 'role_asset_desc' => 'Tato práva řídí přístup k dílům v rámci systému. Specifická práva na knihách, kapitolách a stránkách překryjí tato nastavení.',
+ 'role_asset_admins' => 'Administrátoři automaticky dostávají přístup k veškerému obsahu, ale tyto volby mohou ukázat nebo skrýt volby v uživatelském rozhraní.',
+ 'role_all' => 'Vše',
+ 'role_own' => 'Vlastní',
+ 'role_controlled_by_asset' => 'Řídí se dílem do kterého jsou nahrávány',
+ 'role_save' => 'Uloži roli',
+ 'role_update_success' => 'Role úspěšně aktualizována',
+ 'role_users' => 'Uživatelé mající tuto roli',
+ 'role_users_none' => 'Žádný uživatel nemá tuto roli.',
+
+ // Users
+ 'users' => 'Uživatelé',
+ 'user_profile' => 'Profil uživatele',
+ 'users_add_new' => 'Přidat nového uživatele',
+ 'users_search' => 'Vyhledávání uživatelů',
+ 'users_role' => 'Uživatelské role',
+ 'users_external_auth_id' => 'Přihlašovací identifikátory třetích stran',
+ 'users_password_warning' => 'Vyplňujte pouze v případě, že chcete heslo změnit:',
+ 'users_system_public' => 'Symbolizuje libovolného veřejného návštěvníka, který navštívil vaší aplikaci. Nelze ho použít k přihlášení ale je přiřazen automaticky veřejnosti.',
+ 'users_delete' => 'Smazat uživatele',
+ 'users_delete_named' => 'Smazat uživatele :userName',
+ 'users_delete_warning' => 'Uživatel \':userName\' bude úplně smazán ze systému.',
+ 'users_delete_confirm' => 'Opravdu chcete tohoto uživatele smazat?',
+ 'users_delete_success' => 'Uživatel byl úspěšně smazán',
+ 'users_edit' => 'Upravit uživatele',
+ 'users_edit_profile' => 'Upravit profil',
+ 'users_edit_success' => 'Uživatel byl úspěšně aktualizován',
+ 'users_avatar' => 'Uživatelský obrázek',
+ 'users_avatar_desc' => 'Obrázek by měl být čtverec 256 pixelů široký. Bude oříznut do kruhu.',
+ 'users_preferred_language' => 'Upřednostňovaný jazyk',
+ 'users_social_accounts' => 'Přidružené účty ze sociálních sítí',
+ 'users_social_accounts_info' => 'Zde můžete přidat vaše účty ze sociálních sítí pro pohodlnější přihlašování. Zrušení přidružení zde neznamená, že tato aplikace pozbude práva číst detaily z vašeho účtu. Zakázat této aplikaci přístup k detailům vašeho účtu musíte přímo ve vašem profilu na dané sociální síti.',
+
+ 'users_social_connect' => 'Přidružit účet',
+ 'users_social_disconnect' => 'Zrušit přidružení',
+ 'users_social_connected' => 'Účet :socialAccount byl úspěšně přidružen k vašemu profilu.',
+ 'users_social_disconnected' => 'Přidružení účtu :socialAccount k vašemu profilu bylo úspěšně zrušeno.'
+];
--- /dev/null
+<?php
+
+return [
+ /*
+ |--------------------------------------------------------------------------
+ | Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines contain the default error messages used by
+ | the validator class. Some of these rules have multiple versions such
+ | as the size rules. Feel free to tweak each of these messages.
+ |
+ */
+
+ 'accepted' => ':attribute musí být přijat.',
+ 'active_url' => ':attribute není platnou URL adresou.',
+ 'after' => ':attribute musí být datum po :date.',
+ 'after_or_equal' => ':attribute musí být datum :date nebo pozdější.',
+ 'alpha' => ':attribute může obsahovat pouze písmena.',
+ 'alpha_dash' => ':attribute může obsahovat pouze písmena, číslice, pomlčky a podtržítka. České znaky (á, é, í, ó, ú, ů, ž, š, č, ř, ď, ť, ň) nejsou podporovány.',
+ 'alpha_num' => ':attribute může obsahovat pouze písmena a číslice.',
+ 'array' => ':attribute musí být pole.',
+ 'before' => ':attribute musí být datum před :date.',
+ 'before_or_equal' => 'Datum :attribute musí být před nebo rovno :date.',
+ 'between' => [
+ 'numeric' => ':attribute musí být hodnota mezi :min a :max.',
+ 'file' => ':attribute musí být větší než :min a menší než :max Kilobytů.',
+ 'string' => ':attribute musí být delší než :min a kratší než :max znaků.',
+ 'array' => ':attribute musí obsahovat nejméně :min a nesmí obsahovat více než :max prvků.',
+ ],
+ 'boolean' => ':attribute musí být true nebo false',
+ 'confirmed' => ':attribute nesouhlasí.',
+ 'date' => ':attribute musí být platné datum.',
+ 'date_equals' => 'The :attribute must be a date equal to :date.',
+ 'date_format' => ':attribute není platný formát data podle :format.',
+ 'different' => ':attribute a :other se musí lišit.',
+ 'digits' => ':attribute musí být :digits pozic dlouhé.',
+ 'digits_between' => ':attribute musí být dlouhé nejméně :min a nejvíce :max pozic.',
+ 'dimensions' => ':attribute má neplatné rozměry.',
+ 'distinct' => ':attribute má duplicitní hodnotu.',
+ 'email' => ':attribute není platný formát.',
+ 'exists' => 'Zvolená hodnota pro :attribute není platná.',
+ 'file' => ':attribute musí být soubor.',
+ 'filled' => ':attribute musí být vyplněno.',
+ 'gt' => [
+ 'numeric' => ':attribute musí být větší než :value.',
+ 'file' => 'Velikost souboru :attribute musí být větší než :value kB.',
+ 'string' => 'Počet znaků :attribute musí být větší :value.',
+ 'array' => 'Pole :attribute musí mít více prvků než :value.',
+ ],
+ 'gte' => [
+ 'numeric' => ':attribute musí být větší nebo rovno :value.',
+ 'file' => 'Velikost souboru :attribute musí být větší nebo rovno :value kB.',
+ 'string' => 'Počet znaků :attribute musí být větší nebo rovno :value.',
+ 'array' => 'Pole :attribute musí mít :value prvků nebo více.',
+ ],
+ 'image' => ':attribute musí být obrázek.',
+ 'in' => 'Zvolená hodnota pro :attribute je neplatná.',
+ 'in_array' => ':attribute není obsažen v :other.',
+ 'integer' => ':attribute musí být celé číslo.',
+ 'ip' => ':attribute musí být platnou IP adresou.',
+ 'ipv4' => ':attribute musí být platná IPv4 adresa.',
+ 'ipv6' => ':attribute musí být platná IPv6 adresa.',
+ 'json' => ':attribute musí být platný JSON řetězec.',
+ 'lt' => [
+ 'numeric' => ':attribute musí být menší než :value.',
+ 'file' => 'Velikost souboru :attribute musí být menší než :value kB.',
+ 'string' => ':attribute musí obsahovat méně než :value znaků.',
+ 'array' => ':attribute by měl obsahovat méně než :value položek.',
+ ],
+ 'lte' => [
+ 'numeric' => ':attribute musí být menší nebo rovno než :value.',
+ 'file' => 'Velikost souboru :attribute musí být menší než :value kB.',
+ 'string' => ':attribute nesmí být delší než :value znaků.',
+ 'array' => ':attribute by měl obsahovat maximálně :value položek.',
+ ],
+ 'max' => [
+ 'numeric' => ':attribute nemůže být větší než :max.',
+ 'file' => 'Velikost souboru :attribute musí být menší než :value kB.',
+ 'string' => ':attribute nemůže být delší než :max znaků.',
+ 'array' => ':attribute nemůže obsahovat více než :max prvků.',
+ ],
+ 'mimes' => ':attribute musí být jeden z následujících datových typů :values.',
+ 'mimetypes' => ':attribute musí být jeden z následujících datových typů :values.',
+ 'min' => [
+ 'numeric' => ':attribute musí být větší než :min.',
+ 'file' => ':attribute musí být větší než :min kB.',
+ 'string' => ':attribute musí být delší než :min znaků.',
+ 'array' => ':attribute musí obsahovat více než :min prvků.',
+ ],
+ 'not_in' => 'Zvolená hodnota pro :attribute je neplatná.',
+ 'not_regex' => ':attribute musí být regulární výraz.',
+ 'numeric' => ':attribute musí být číslo.',
+ 'present' => ':attribute musí být vyplněno.',
+ 'regex' => ':attribute nemá správný formát.',
+ 'required' => ':attribute musí být vyplněno.',
+ 'required_if' => ':attribute musí být vyplněno pokud :other je :value.',
+ 'required_unless' => ':attribute musí být vyplněno dokud :other je v :values.',
+ 'required_with' => ':attribute musí být vyplněno pokud :values je vyplněno.',
+ 'required_with_all' => ':attribute musí být vyplněno pokud :values je zvoleno.',
+ 'required_without' => ':attribute musí být vyplněno pokud :values není vyplněno.',
+ 'required_without_all' => ':attribute musí být vyplněno pokud není žádné z :values zvoleno.',
+ 'same' => ':attribute a :other se musí shodovat.',
+ 'size' => [
+ 'numeric' => ':attribute musí být přesně :size.',
+ 'file' => ':attribute musí mít přesně :size Kilobytů.',
+ 'string' => ':attribute musí být přesně :size znaků dlouhý.',
+ 'array' => ':attribute musí obsahovat právě :size prvků.',
+ ],
+ 'starts_with' => 'The :attribute must start with one of the following: :values',
+ 'string' => ':attribute musí být řetězec znaků.',
+ 'timezone' => ':attribute musí být platná časová zóna.',
+ 'unique' => ':attribute musí být unikátní.',
+ 'uploaded' => 'Nahrávání :attribute se nezdařilo.',
+ 'url' => 'Formát :attribute je neplatný.',
+ 'uuid' => ':attribute musí být validní UUID.',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute.rule" to name the lines. This makes it quick to
+ | specify a specific custom language line for a given attribute rule.
+ |
+ */
+
+ 'custom' => [
+ 'attribute-name' => [
+ 'rule-name' => 'custom-message',
+ ],
+ 'password-confirm' => [
+ 'required_with' => 'Password confirmation required',
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap attribute place-holders
+ | with something more reader friendly such as E-Mail Address instead
+ | of "email". This simply helps us make messages a little cleaner.
+ |
+ */
+
+ 'attributes' => [
+ 'password' => 'heslo',
+ ],
+];
'save' => 'Save',
'continue' => 'Continue',
'select' => 'Select',
+ 'toggle_all' => 'Toggle All',
'more' => 'More',
// Form Labels
// Actions
'actions' => 'Actions',
'view' => 'View',
+ 'view_all' => 'View All',
'create' => 'Create',
'update' => 'Update',
'edit' => 'Edit',
'remove' => 'Remove',
'add' => 'Add',
+ // Sort Options
+ 'sort_name' => 'Name',
+ 'sort_created_at' => 'Created Date',
+ 'sort_updated_at' => 'Updated Date',
+
// Misc
'deleted_user' => 'Deleted User',
'no_activity' => 'No activity to show',
'view_profile' => 'View Profile',
'edit_profile' => 'Edit Profile',
+ // Layout tabs
+ 'tab_info' => 'Info',
+ 'tab_content' => 'Content',
+
// Email Content
'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:',
'email_rights' => 'All rights reserved',
-];
\ No newline at end of file
+];
'recently_updated_pages' => 'Recently Updated Pages',
'recently_created_chapters' => 'Recently Created Chapters',
'recently_created_books' => 'Recently Created Books',
+ 'recently_created_shelves' => 'Recently Created Shelves',
'recently_update' => 'Recently Updated',
'recently_viewed' => 'Recently Viewed',
'recent_activity' => 'Recent Activity',
// Shelves
'shelf' => 'Shelf',
'shelves' => 'Shelves',
+ 'x_shelves' => ':count Shelf|:count Shelves',
'shelves_long' => 'Bookshelves',
'shelves_empty' => 'No shelves have been created',
'shelves_create' => 'Create New Shelf',
'shelves_popular' => 'Popular Shelves',
'shelves_new' => 'New Shelves',
+ 'shelves_new_action' => 'New Shelf',
'shelves_popular_empty' => 'The most popular shelves will appear here.',
'shelves_new_empty' => 'The most recently created shelves will appear here.',
'shelves_save' => 'Save Shelf',
'books_popular' => 'Popular Books',
'books_recent' => 'Recent Books',
'books_new' => 'New Books',
+ 'books_new_action' => 'New Book',
'books_popular_empty' => 'The most popular books will appear here.',
'books_new_empty' => 'The most recently created books will appear here.',
'books_create' => 'Create New Book',
'books_permissions_updated' => 'Book Permissions Updated',
'books_empty_contents' => 'No pages or chapters have been created for this book.',
'books_empty_create_page' => 'Create a new page',
- 'books_empty_or' => 'or',
'books_empty_sort_current_book' => 'Sort the current book',
'books_empty_add_chapter' => 'Add a chapter',
'books_permissions_active' => 'Book Permissions Active',
'books_navigation' => 'Book Navigation',
'books_sort' => 'Sort Book Contents',
'books_sort_named' => 'Sort Book :bookName',
+ 'books_sort_name' => 'Sort by Name',
+ 'books_sort_created' => 'Sort by Created Date',
+ 'books_sort_updated' => 'Sort by Updated Date',
+ 'books_sort_chapters_first' => 'Chapters First',
+ 'books_sort_chapters_last' => 'Chapters Last',
'books_sort_show_other' => 'Show Other Books',
'books_sort_save' => 'Save New Order',
'pages_revisions_created_by' => 'Created By',
'pages_revisions_date' => 'Revision Date',
'pages_revisions_number' => '#',
+ 'pages_revisions_numbered' => 'Revision #:id',
+ 'pages_revisions_numbered_changes' => 'Revision #:id Changes',
'pages_revisions_changelog' => 'Changelog',
'pages_revisions_changes' => 'Changes',
'pages_revisions_current' => 'Current Version',
'profile_not_created_pages' => ':userName has not created any pages',
'profile_not_created_chapters' => ':userName has not created any chapters',
'profile_not_created_books' => ':userName has not created any books',
+ 'profile_not_created_shelves' => ':userName has not created any shelves',
// Comments
'comment' => 'Comment',
// Revision
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
+ 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.',
'revision_delete_success' => 'Revision deleted',
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.'
];
\ No newline at end of file
'settings_save_success' => 'Settings saved',
// App Settings
- 'app_settings' => 'App Settings',
- 'app_name' => 'Application name',
- 'app_name_desc' => 'This name is shown in the header and any emails.',
- 'app_name_header' => 'Show Application name in header?',
+ 'app_customization' => 'Customization',
+ 'app_features_security' => 'Features & Security',
+ 'app_name' => 'Application Name',
+ 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.',
+ 'app_name_header' => 'Show name in header',
+ 'app_public_access' => 'Public Access',
+ 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.',
+ 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.',
+ 'app_public_access_toggle' => 'Allow public access',
'app_public_viewing' => 'Allow public viewing?',
- 'app_secure_images' => 'Enable higher security image uploads?',
+ 'app_secure_images' => 'Higher Security Image Uploads',
+ 'app_secure_images_toggle' => 'Enable higher security image uploads',
'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.',
- 'app_editor' => 'Page editor',
+ 'app_editor' => 'Page Editor',
'app_editor_desc' => 'Select which editor will be used by all users to edit pages.',
- 'app_custom_html' => 'Custom HTML head content',
+ 'app_custom_html' => 'Custom HTML Head Content',
'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the <head> section of every page. This is handy for overriding styles or adding analytics code.',
- 'app_logo' => 'Application logo',
+ 'app_logo' => 'Application Logo',
'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
- 'app_primary_color' => 'Application primary color',
+ 'app_primary_color' => 'Application Primary Color',
'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
'app_homepage' => 'Application Homepage',
'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
'app_homepage_select' => 'Select a page',
- 'app_disable_comments' => 'Disable comments',
- 'app_disable_comments_desc' => 'Disable comments across all pages in the application. Existing comments are not shown.',
+ 'app_disable_comments' => 'Disable Comments',
+ 'app_disable_comments_toggle' => 'Disable comments',
+ 'app_disable_comments_desc' => 'Disables comments across all pages in the application. <br> Existing comments are not shown.',
// Registration Settings
- 'reg_settings' => 'Registration Settings',
- 'reg_allow' => 'Allow registration?',
+ 'reg_settings' => 'Registration',
+ 'reg_enable' => 'Enable Registration',
+ 'reg_enable_toggle' => 'Enable registration',
+ 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.',
'reg_default_role' => 'Default user role after registration',
- 'reg_confirm_email' => 'Require email confirmation?',
- 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and the below value will be ignored.',
- 'reg_confirm_restrict_domain' => 'Restrict registration to domain',
+ 'reg_email_confirmation' => 'Email Confirmation',
+ 'reg_email_confirmation_toggle' => 'Require email confirmation',
+ 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.',
+ 'reg_confirm_restrict_domain' => 'Domain Restriction',
'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
'user_profile' => 'User Profile',
'users_add_new' => 'Add New User',
'users_search' => 'Search Users',
+ 'users_details' => 'User Details',
+ 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.',
+ 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.',
'users_role' => 'User Roles',
+ 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.',
+ 'users_password' => 'User Password',
+ 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 5 characters long.',
'users_external_auth_id' => 'External Authentication ID',
- 'users_password_warning' => 'Only fill the below if you would like to change your password:',
+ 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.',
+ 'users_password_warning' => 'Only fill the below if you would like to change your password.',
'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.',
'users_delete' => 'Delete User',
'users_delete_named' => 'Delete user :userName',
'users_edit_profile' => 'Edit Profile',
'users_edit_success' => 'User successfully updated',
'users_avatar' => 'User Avatar',
- 'users_avatar_desc' => 'This image should be approx 256px square.',
+ 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.',
'users_preferred_language' => 'Preferred Language',
+ 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.',
'users_social_accounts' => 'Social Accounts',
'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.',
'users_social_connect' => 'Connect Account',
'nl' => 'Nederlands',
'pt_BR' => 'Português do Brasil',
'sk' => 'Slovensky',
+ 'cs' => 'Česky',
'sv' => 'Svenska',
'kr' => '한국어',
'ja' => '日本語',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
+ 'no_double_extension' => 'The :attribute must only have a single file extension.',
'not_in' => 'The selected :attribute is invalid.',
'numeric' => 'The :attribute must be a number.',
'regex' => 'The :attribute format is invalid.',
'role_cannot_be_edited' => 'Este rol no puede ser editado',
'role_system_cannot_be_deleted' => 'Este rol es un rol de sistema y no puede ser borrado',
'role_registration_default_cannot_delete' => 'Este rol no puede ser borrado mientras sea el rol por defecto de registro',
+ 'role_cannot_remove_only_admin' => 'Este usuario es el único asignado al rol de administrador. Asigne el rol de administrador a otro usuario antes de intentar eliminarlo.',
// Comments
'comment_list' => 'Se produjo un error al obtener los comentarios.',
'timezone' => 'El atributo :attribute debe ser una zona válida.',
'unique' => 'El atributo :attribute ya ha sido tomado.',
'url' => 'El atributo :attribute tiene un formato inválid.',
+ 'is_image' => 'El atributo :attribute debe ser una imagen válida.',
/*
|--------------------------------------------------------------------------
'books_sort_show_other' => 'Показать другие книги',
'books_sort_save' => 'Сохранить новый порядок',
+ /**
+ * Shelves
+ */
+ 'shelf' => 'Полка',
+ 'shelves' => 'Полки',
+ 'shelves_long' => 'Книжные полки',
+ 'shelves_empty' => 'Полки не созданы',
+ 'shelves_create' => 'Создать новую полку',
+ 'shelves_popular' => 'Популярные полки',
+ 'shelves_new' => 'Новые полки',
+ 'shelves_popular_empty' => 'Популярные полки появятся здесь.',
+ 'shelves_new_empty' => 'Последние созданные полки появятся здесь.',
+ 'shelves_save' => 'Сохранить полку',
+ 'shelves_books' => 'Книги из этой полки',
+ 'shelves_add_books' => 'Добавить книгу в эту полку',
+ 'shelves_drag_books' => 'Перетащите книгу сюда, чтобы добавить на эту полку',
+ 'shelves_empty_contents' => 'На этой полке нет книг',
+ 'shelves_edit_and_assign' => 'Изменить полку для привязки книг',
+ 'shelves_edit_named' => 'Редактировать полку :name',
+ 'shelves_edit' => 'Редактировать книжную полку',
+ 'shelves_delete' => 'Удалить книжную полку',
+ 'shelves_delete_named' => 'Удалить книжную полку :name',
+ 'shelves_delete_explain' => "Это приведет к удалению полки с именем ':name'. Привязанные книги удалены не будут.",
+ 'shelves_delete_confirmation' => 'Вы уверены, что хотите удалить эту полку?',
+ 'shelves_permissions' => 'Доступы к книжной полке',
+ 'shelves_permissions_updated' => 'Доступы к книжной полке обновлены',
+ 'shelves_permissions_active' => 'Доступы к книжной полке активны',
+ 'shelves_copy_permissions_to_books' => 'Наследовать доступы книгам',
+ 'shelves_copy_permissions' => 'Копировать доступы',
+ 'shelves_copy_permissions_explain' => 'Это применит текущие настройки доступов этой книжной полки ко всем книгам, содержащимся внутри. Перед активацией убедитесь, что все изменения в доступах этой книжной полки сохранены.',
+ 'shelves_copy_permission_success' => 'Доступы книжной полки скопированы для :count books',
+
/**
* Chapters
*/
'page_tags' => 'Теги страницы',
'chapter_tags' => 'Теги главы',
'book_tags' => 'Теги книги',
+ 'shelf_tags' => 'Теги полки',
'tag' => 'Тег',
'tags' => 'Теги',
'tag_value' => 'Значение тега (опционально)',
<div class="form-group">
<label for="username">{{ trans('auth.username') }}</label>
- @include('form/text', ['name' => 'username', 'tabindex' => 1])
+ @include('form.text', ['name' => 'username', 'tabindex' => 1])
</div>
@if(session('request-email', false) === true)
<div class="form-group">
<label for="email">{{ trans('auth.email') }}</label>
- @include('form/text', ['name' => 'email', 'tabindex' => 1])
+ @include('form.text', ['name' => 'email', 'tabindex' => 1])
<span class="text-neg">
{{ trans('auth.ldap_email_hint') }}
</span>
<div class="form-group">
<label for="password">{{ trans('auth.password') }}</label>
- @include('form/password', ['name' => 'password', 'tabindex' => 2])
+ @include('form.password', ['name' => 'password', 'tabindex' => 2])
</div>
\ No newline at end of file
<div class="form-group">
<label for="email">{{ trans('auth.email') }}</label>
- @include('form/text', ['name' => 'email', 'tabindex' => 1])
+ @include('form.text', ['name' => 'email', 'tabindex' => 1])
</div>
<div class="form-group">
<label for="password">{{ trans('auth.password') }}</label>
- @include('form/password', ['name' => 'password', 'tabindex' => 2])
- <span class="block small"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
+ @include('form.password', ['name' => 'password', 'tabindex' => 1])
+ <span class="block small mt-s"><a href="{{ baseUrl('/password/email') }}">{{ trans('auth.forgot_password') }}</a></span>
</div>
\ No newline at end of file
-@extends('public')
-
-@section('header-buttons')
- @if(setting('registration-enabled', false))
- <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
- @endif
-@stop
+@extends('simple-layout')
@section('content')
- <div class="text-center">
- <div class="card center-box">
- <h3>@icon('login') {{ title_case(trans('auth.log_in')) }}</h3>
+ <div class="container very-small">
- <div class="body">
- <form action="{{ baseUrl("/login") }}" method="POST" id="login-form">
- {!! csrf_field() !!}
+ <div class="my-l"> </div>
- @include('auth/forms/login/' . $authMethod)
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ title_case(trans('auth.log_in')) }}</h1>
- <div class="form-group">
- <label for="remember" class="inline">{{ trans('auth.remember_me') }}</label>
- <input type="checkbox" id="remember" name="remember" class="toggle-switch-checkbox">
- <label for="remember" class="toggle-switch"></label>
- </div>
+ <form action="{{ baseUrl("/login") }}" method="POST" id="login-form" class="mt-l">
+ {!! csrf_field() !!}
+
+ <div class="stretch-inputs">
+ @include('auth.forms.login.' . $authMethod)
+ </div>
- <div class="from-group">
- <button class="button block pos" tabindex="3">@icon('login') {{ title_case(trans('auth.log_in')) }}</button>
+ <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>
- </form>
+ <div class="text-right">
+ <button class="button primary" tabindex="3">{{ title_case(trans('auth.log_in')) }}</button>
+ </div>
+ </div>
+
+ </form>
- @if(count($socialDrivers) > 0)
- <hr class="margin-top">
- @foreach($socialDrivers as $driver => $name)
- <a id="social-login-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/login/service/" . $driver) }}">
+ @if(count($socialDrivers) > 0)
+ <hr class="my-l">
+ @foreach($socialDrivers as $driver => $name)
+ <div>
+ <a id="social-login-{{$driver}}" class="button outline block svg" href="{{ baseUrl("/login/service/" . $driver) }}">
@icon('auth/' . $driver)
{{ trans('auth.log_in_with', ['socialDriver' => $name]) }}
</a>
- @endforeach
- @endif
- </div>
+ </div>
+ @endforeach
+ @endif
</div>
</div>
-@extends('public')
-
-@section('header-buttons')
- <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
- @if(setting('registration-enabled'))
- <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
- @endif
-@stop
+@extends('simple-layout')
@section('content')
+ <div class="container very-small mt-xl">
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('auth.reset_password') }}</h1>
+ <p class="text-muted small">{{ trans('auth.reset_password_send_instructions') }}</p>
- <div class="text-center">
- <div class="card center-box">
- <h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
-
- <div class="body">
- <p class="muted small">{{ trans('auth.reset_password_send_instructions') }}</p>
+ <form action="{{ baseUrl("/password/email") }}" method="POST" class="stretch-inputs">
+ {!! csrf_field() !!}
- <form action="{{ baseUrl("/password/email") }}" method="POST">
- {!! csrf_field() !!}
+ <div class="form-group">
+ <label for="email">{{ trans('auth.email') }}</label>
+ @include('form.text', ['name' => 'email'])
+ </div>
- <div class="form-group">
- <label for="email">{{ trans('auth.email') }}</label>
- @include('form/text', ['name' => 'email'])
- </div>
-
- <div class="from-group text-right">
- <button class="button primary">{{ trans('auth.reset_password_send_button') }}</button>
- </div>
- </form>
- </div>
+ <div class="from-group text-right mt-m">
+ <button class="button primary">{{ trans('auth.reset_password_send_button') }}</button>
+ </div>
+ </form>
</div>
</div>
-
@stop
\ No newline at end of file
-@extends('public')
-
-@section('header-buttons')
- <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
- @if(setting('registration-enabled'))
- <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
- @endif
-@stop
+@extends('simple-layout')
@section('content')
- <div class="text-center">
- <div class="card center-box">
- <h3>@icon('permission') {{ trans('auth.reset_password') }}</h3>
-
- <div class="body">
- <form action="{{ baseUrl("/password/reset") }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="token" value="{{ $token }}">
-
- <div class="form-group">
- <label for="email">{{ trans('auth.email') }}</label>
- @include('form/text', ['name' => 'email'])
- </div>
-
- <div class="form-group">
- <label for="password">{{ trans('auth.password') }}</label>
- @include('form/password', ['name' => 'password'])
- </div>
-
- <div class="form-group">
- <label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
- @include('form/password', ['name' => 'password_confirmation'])
- </div>
-
- <div class="from-group text-right">
- <button class="button primary">{{ trans('auth.reset_password') }}</button>
- </div>
- </form>
- </div>
+ <div class="container very-small mt-xl">
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('auth.reset_password') }}</h1>
+
+ <form action="{{ baseUrl("/password/reset") }}" method="POST" class="stretch-inputs">
+ {!! csrf_field() !!}
+ <input type="hidden" name="token" value="{{ $token }}">
+
+ <div class="form-group">
+ <label for="email">{{ trans('auth.email') }}</label>
+ @include('form.text', ['name' => 'email'])
+ </div>
+
+ <div class="form-group">
+ <label for="password">{{ trans('auth.password') }}</label>
+ @include('form.password', ['name' => 'password'])
+ </div>
+
+ <div class="form-group">
+ <label for="password_confirmation">{{ trans('auth.password_confirm') }}</label>
+ @include('form.password', ['name' => 'password_confirmation'])
+ </div>
+
+ <div class="from-group text-right mt-m">
+ <button class="button primary">{{ trans('auth.reset_password') }}</button>
+ </div>
+ </form>
</div>
</div>
-@extends('public')
-
-@section('header-buttons')
- @if(!$signedIn)
- <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
- @endif
-@stop
+@extends('simple-layout')
@section('content')
- <div class="text-center">
- <div class="card center-box">
- <h3>@icon('users') {{ trans('auth.register_thanks') }}</h3>
- <div class="body">
- <p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
- </div>
+ <div class="container very-small mt-xl">
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('auth.register_thanks') }}</h1>
+ <p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
</div>
</div>
-@extends('public')
-
-@section('header-buttons')
- <a href="{{ baseUrl("/login") }}">@icon('login') {{ trans('auth.log_in') }}</a>
-@stop
+@extends('simple-layout')
@section('content')
+ <div class="container very-small">
- <div class="text-center">
- <div class="card center-box">
- <h3>@icon('new-user') {{ title_case(trans('auth.sign_up')) }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/register") }}" method="POST">
- {!! csrf_field() !!}
+ <div class="my-l"> </div>
- <div class="form-group">
- <label for="email">{{ trans('auth.name') }}</label>
- @include('form/text', ['name' => 'name'])
- </div>
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ title_case(trans('auth.sign_up')) }}</h1>
- <div class="form-group">
- <label for="email">{{ trans('auth.email') }}</label>
- @include('form/text', ['name' => 'email'])
- </div>
+ <form action="{{ baseUrl("/register") }}" method="POST" class="mt-l stretch-inputs">
+ {!! csrf_field() !!}
- <div class="form-group">
- <label for="password">{{ trans('auth.password') }}</label>
- @include('form/password', ['name' => 'password', 'placeholder' => trans('auth.password_hint')])
- </div>
+ <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="from-group">
- <button class="button block pos">{{ trans('auth.create_account') }}</button>
+ <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>
- </form>
+ <div class="from-group text-right">
+ <button class="button primary">{{ trans('auth.create_account') }}</button>
+ </div>
+ </div>
+
+
+ </form>
- @if(count($socialDrivers) > 0)
- <hr class="margin-top">
- @foreach($socialDrivers as $driver => $name)
- <a id="social-register-{{$driver}}" class="button block muted-light svg text-left" href="{{ baseUrl("/register/service/" . $driver) }}">
+ @if(count($socialDrivers) > 0)
+ <hr class="my-l">
+ @foreach($socialDrivers as $driver => $name)
+ <div>
+ <a id="social-register-{{$driver}}" class="button block outline svg" href="{{ baseUrl("/register/service/" . $driver) }}">
@icon('auth/' . $driver)
{{ trans('auth.sign_up_with', ['socialDriver' => $name]) }}
</a>
- @endforeach
- @endif
- </div>
+ </div>
+ @endforeach
+ @endif
</div>
</div>
-
-
@stop
-@extends('public')
+@extends('simple-layout')
@section('content')
- <div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('users') {{ trans('auth.email_not_confirmed') }}</h3>
- <div class="body">
- <p class="text-muted">{{ trans('auth.email_not_confirmed_text') }}<br>
- {{ trans('auth.email_not_confirmed_click_link') }} <br>
- {{ trans('auth.email_not_confirmed_resend') }}
- </p>
- <hr>
- <form action="{{ baseUrl("/register/confirm/resend") }}" method="POST">
- {!! csrf_field() !!}
- <div class="form-group">
- <label for="email">{{ trans('auth.email') }}</label>
- @if(auth()->check())
- @include('form/text', ['name' => 'email', 'model' => auth()->user()])
- @else
- @include('form/text', ['name' => 'email'])
- @endif
- </div>
- <div class="form-group">
- <button type="submit" class="button pos">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
- </div>
- </form>
- </div>
- </div>
+ <div class="container very-small mt-xl">
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('auth.email_not_confirmed') }}</h1>
+
+ <p>{{ trans('auth.email_not_confirmed_text') }}<br>
+ {{ trans('auth.email_not_confirmed_click_link') }}
+ </p>
+ <p>
+ {{ trans('auth.email_not_confirmed_resend') }}
+ </p>
+ <form action="{{ baseUrl("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
+ {!! csrf_field() !!}
+ <div class="form-group">
+ <label for="email">{{ trans('auth.email') }}</label>
+ @if(auth()->check())
+ @include('form.text', ['name' => 'email', 'model' => auth()->user()])
+ @else
+ @include('form.text', ['name' => 'email'])
+ @endif
+ </div>
+ <div class="form-group text-right mt-m">
+ <button type="submit" class="button primary">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
+ </div>
+ </form>
+
+ </div>
</div>
@stop
<script src="{{ baseUrl('/translations') }}"></script>
@yield('head')
-
- @include('partials/custom-styles')
-
+ @include('partials.custom-styles')
@include('partials.custom-head')
-</head>
-<body class="@yield('body-class')" ng-app="bookStack">
-
- @include('partials/notifications')
- <header id="header">
- <div class="container fluid">
- <div class="row">
- <div class="col-sm-4 col-md-3">
- <a href="{{ baseUrl('/') }}" class="logo">
- @if(setting('app-logo', '') !== 'none')
- <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
- @endif
- @if (setting('app-name-header'))
- <span class="logo-text">{{ setting('app-name') }}</span>
- @endif
- </a>
- </div>
- <div class="col-sm-8 col-md-9">
- <div class="float right">
- <div class="header-search">
- <form action="{{ baseUrl('/search') }}" method="GET" class="search-box">
- <button id="header-search-box-button" type="submit">@icon('search') </button>
- <input id="header-search-box-input" type="text" name="term" tabindex="2" placeholder="{{ trans('common.search') }}" value="{{ isset($searchTerm) ? $searchTerm : '' }}">
- </form>
- </div>
- <div class="links text-center">
- @if(userCanOnAny('view', \BookStack\Entities\Bookshelf::class) || userCan('bookshelf-view-own'))
- <a href="{{ baseUrl('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
- @endif
- <a href="{{ baseUrl('/books') }}">@icon('book'){{ trans('entities.books') }}</a>
- @if(signedInUser() && userCan('settings-manage'))
- <a href="{{ baseUrl('/settings') }}">@icon('settings'){{ trans('settings.settings') }}</a>
- @endif
- @if(signedInUser() && userCan('users-manage') && !userCan('settings-manage'))
- <a href="{{ baseUrl('/settings/users') }}">@icon('users'){{ trans('settings.users') }}</a>
- @endif
- @if(!signedInUser())
- @if(setting('registration-enabled', false))
- <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
- @endif
- <a href="{{ baseUrl('/login') }}">@icon('login') {{ trans('auth.log_in') }}</a>
- @endif
- </div>
- @if(signedInUser())
- @include('partials._header-dropdown', ['currentUser' => user()])
- @endif
+ @stack('head')
+</head>
+<body class="@yield('body-class')">
- </div>
- </div>
- </div>
- </div>
- </header>
+ @include('partials.notifications')
+ @include('common.header')
<section id="content" class="block">
@yield('content')
</section>
- <div back-to-top>
+ <div back-to-top class="primary-background">
<div class="inner">
@icon('chevron-up') <span>{{ trans('common.back_to_top') }}</span>
</div>
</div>
-@yield('bottom')
-<script src="{{ versioned_asset('dist/app.js') }}"></script>
-@yield('scripts')
+
+ @yield('bottom')
+ <script src="{{ versioned_asset('dist/app.js') }}"></script>
+ @yield('scripts')
+
</body>
</html>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-8 faded">
- <div class="breadcrumbs">
- <a href="{{ baseUrl('/books') }}" class="text-button">@icon('book'){{ trans('entities.books') }}</a>
- <span class="sep">»</span>
- <a href="{{ baseUrl('/create-book') }}" class="text-button">@icon('add'){{ trans('entities.books_create') }}</a>
- </div>
- </div>
-@stop
-
@section('body')
+ <div class="container small">
+ <div class="my-s">
+ @if (isset($bookshelf))
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $bookshelf,
+ $bookshelf->getUrl('/create-book') => [
+ 'text' => trans('entities.books_create'),
+ 'icon' => 'add'
+ ]
+ ]])
+ @else
+ @include('partials.breadcrumbs', ['crumbs' => [
+ '/books' => [
+ 'text' => trans('entities.books'),
+ 'icon' => 'book'
+ ],
+ '/create-book' => [
+ 'text' => trans('entities.books_create'),
+ 'icon' => 'add'
+ ]
+ ]])
+ @endif
+ </div>
-<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('add') {{ trans('entities.books_create') }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
- @include('books/form')
+ <div class="content-wrap card">
+ <h1 class="list-heading">{{ trans('entities.books_create') }}</h1>
+ <form action="{{ isset($bookshelf) ? $bookshelf->getUrl('/create-book') : baseUrl('/books') }}" method="POST" enctype="multipart/form-data">
+ @include('books.form')
</form>
</div>
</div>
-</div>
-<p class="margin-top large"><br></p>
+
@include('components.image-manager', ['imageType' => 'cover'])
@stop
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('books._breadcrumbs', ['book' => $book])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ trans('entities.books_delete') }}</h3>
- <div class="body">
- <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p>
- <p class="text-neg">{{ trans('entities.books_delete_confirmation') }}</p>
- <form action="{{$book->getUrl()}}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
- <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
- </form>
- </div>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ $book->getUrl('/delete') => [
+ 'text' => trans('entities.books_delete'),
+ 'icon' => 'delete',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('entities.books_delete') }}</h1>
+ <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p>
+ <p class="text-neg"><strong>{{ trans('entities.books_delete_confirmation') }}</strong></p>
+
+ <form action="{{$book->getUrl()}}" method="POST" class="text-right">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
+ <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
+ </form>
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('books._breadcrumbs', ['book' => $book])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('edit') {{ trans('entities.books_edit') }}</h3>
- <div class="body">
- <form action="{{ $book->getUrl() }}" method="POST">
- <input type="hidden" name="_method" value="PUT">
- @include('books/form', ['model' => $book])
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ $book->getUrl('/edit') => [
+ 'text' => trans('entities.books_edit'),
+ 'icon' => 'edit',
+ ]
+ ]])
+ </div>
+
+ <div class="content-wrap card">
+ <h1 class="list-heading">{{ trans('entities.books_edit') }}</h1>
+ <form action="{{ $book->getUrl() }}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('books.form', ['model' => $book])
+ </form>
</div>
</div>
-@include('components.image-manager', ['imageType' => 'cover'])
+
+ @include('components.image-manager', ['imageType' => 'cover'])
@stop
\ No newline at end of file
@include('partials.custom-head')
</head>
<body>
-<div class="container">
- <div class="row">
- <div class="col-md-8 col-md-offset-2">
- <div class="page-content">
- <h1 style="font-size: 4.8em">{{$book->name}}</h1>
+<div class="page-content">
- <p>{{ $book->description }}</p>
+ <h1 style="font-size: 4.8em">{{$book->name}}</h1>
- @if(count($bookChildren) > 0)
- <ul class="contents">
- @foreach($bookChildren as $bookChild)
- <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
- @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
- <ul>
- @foreach($bookChild->pages as $page)
- <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
- @endforeach
- </ul>
- @endif
- @endforeach
- </ul>
+ <p>{{ $book->description }}</p>
+
+ @if(count($bookChildren) > 0)
+ <ul class="contents">
+ @foreach($bookChildren as $bookChild)
+ <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
+ @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
+ <ul>
+ @foreach($bookChild->pages as $page)
+ <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
+ @endforeach
+ </ul>
@endif
+ @endforeach
+ </ul>
+ @endif
+
+ @foreach($bookChildren as $bookChild)
+ <div class="page-break"></div>
+ <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
- @foreach($bookChildren as $bookChild)
+ @if($bookChild->isA('chapter'))
+ <p>{{ $bookChild->description }}</p>
+
+ @if(count($bookChild->pages) > 0)
+ @foreach($bookChild->pages as $page)
<div class="page-break"></div>
- <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
- @if($bookChild->isA('chapter'))
- <p>{{ $bookChild->description }}</p>
- @if(count($bookChild->pages) > 0)
- @foreach($bookChild->pages as $page)
- <div class="page-break"></div>
- <div class="chapter-hint">{{$bookChild->name}}</div>
- <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
- {!! $page->html !!}
- @endforeach
- @endif
- @else
- {!! $bookChild->html !!}
- @endif
+ <div class="chapter-hint">{{$bookChild->name}}</div>
+ <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
+ {!! $page->html !!}
@endforeach
+ @endif
+
+ @else
+ {!! $bookChild->html !!}
+ @endif
+
+ @endforeach
- </div>
- </div>
- </div>
</div>
+
</body>
</html>
{{ csrf_field() }}
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>
- @include('form/text', ['name' => 'name'])
+ @include('form.text', ['name' => 'name'])
</div>
<div class="form-group description-input">
<label for="description">{{ trans('common.description') }}</label>
- @include('form/textarea', ['name' => 'description'])
+ @include('form.textarea', ['name' => 'description'])
</div>
<div class="form-group" collapsible id="logo-control">
<div class="form-group text-right">
<a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.books_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('entities.books_save') }}</button>
</div>
\ No newline at end of file
-<div class="book-grid-item grid-card" data-entity-type="book" data-entity-id="{{$book->id}}">
- <div class="featured-image-container">
- <a href="{{$book->getUrl()}}" title="{{$book->name}}">
- <img src="{{$book->getBookCover()}}" alt="{{$book->name}}">
- </a>
+<a href="{{$book->getUrl()}}" class="grid-card" data-entity-type="book" data-entity-id="{{$book->id}}">
+ <div class="bg-book featured-image-container-wrap">
+ <div class="featured-image-container" @if($book->cover) style="background-image: url('{{ $book->getBookCover() }}')"@endif>
+ </div>
+ @icon('book')
</div>
<div class="grid-card-content">
- <h2><a class="break-text" href="{{$book->getUrl()}}" title="{{$book->name}}">{{$book->getShortName(35)}}</a></h2>
+ <h2>{{$book->getShortName(35)}}</h2>
@if(isset($book->searchSnippet))
- <p >{!! $book->searchSnippet !!}</p>
+ <p class="text-muted">{!! $book->searchSnippet !!}</p>
@else
- <p >{{ $book->getExcerpt(130) }}</p>
+ <p class="text-muted">{{ $book->getExcerpt(130) }}</p>
@endif
</div>
- <div class="grid-card-footer text-muted text-small">
- <span>@include('partials.entity-meta', ['entity' => $book])</span>
+ <div class="grid-card-footer text-muted ">
+ <p>@icon('star')<span title="{{$book->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $book->created_at->diffForHumans()]) }}</span></p>
+ <p>@icon('edit')<span title="{{ $book->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $book->updated_at->diffForHumans()]) }}</span></p>
</div>
-</div>
\ No newline at end of file
+</a>
\ No newline at end of file
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-xs-6">
- <div class="action-buttons text-left">
- @include('books/view-toggle', ['booksViewType' => $booksViewType])
- </div>
- </div>
- <div class="col-xs-6 faded">
- <div class="action-buttons">
- @if($currentUser->can('book-create-all'))
- <a href="{{ baseUrl("/create-book") }}" class="text-pos text-button">@icon('add'){{ trans('entities.books_create') }}</a>
- @endif
- </div>
- </div>
+@section('container-classes', 'mt-xl')
+
+@section('body')
+ @include('books.list', ['books' => $books, 'view' => $view])
@stop
-@section('sidebar')
+@section('left')
@if($recents)
- <div id="recents" class="card">
- <h3>@icon('view') {{ trans('entities.recently_viewed') }}</h3>
- @include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
+ <div id="recents" class="mb-xl">
+ <h5>{{ trans('entities.recently_viewed') }}</h5>
+ @include('partials.entity-list', ['entities' => $recents, 'style' => 'compact'])
</div>
@endif
- <div id="popular" class="card">
- <h3>@icon('popular') {{ trans('entities.books_popular') }}</h3>
+ <div id="popular" class="mb-xl">
+ <h5>{{ trans('entities.books_popular') }}</h5>
@if(count($popular) > 0)
- @include('partials/entity-list', ['entities' => $popular, 'style' => 'compact'])
+ @include('partials.entity-list', ['entities' => $popular, 'style' => 'compact'])
@else
<div class="body text-muted">{{ trans('entities.books_popular_empty') }}</div>
@endif
</div>
- <div id="new" class="card">
- <h3>@icon('star-circle') {{ trans('entities.books_new') }}</h3>
+ <div id="new" class="mb-xl">
+ <h5>{{ trans('entities.books_new') }}</h5>
@if(count($popular) > 0)
- @include('partials/entity-list', ['entities' => $new, 'style' => 'compact'])
+ @include('partials.entity-list', ['entities' => $new, 'style' => 'compact'])
@else
<div class="body text-muted">{{ trans('entities.books_new_empty') }}</div>
@endif
</div>
@stop
-@section('body')
- @include('books/list', ['books' => $books, 'bookViewType' => $booksViewType])
+@section('right')
+
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
+ @if($currentUser->can('book-create-all'))
+ <a href="{{ baseUrl("/create-book") }}" class="icon-list-item">
+ <span>@icon('add')</span>
+ <span>{{ trans('entities.books_create') }}</span>
+ </a>
+ @endif
+
+ @include('partials.view-toggle', ['view' => $view, 'type' => 'book'])
+ </div>
+ </div>
+
@stop
\ No newline at end of file
-<div class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
- <h4 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}">@icon('book')<span class="entity-list-item-name break-text">{{$book->name}}</span></a></h4>
- <div class="entity-item-snippet">
- @if(isset($book->searchSnippet))
- <p class="text-muted break-text">{!! $book->searchSnippet !!}</p>
- @else
- <p class="text-muted break-text">{{ $book->getExcerpt() }}</p>
- @endif
+<a href="{{ $book->getUrl() }}" class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
+ <div class="entity-list-item-image bg-book" style="background-image: url('{{ $book->getBookCover() }}')">
+ @icon('book')
</div>
-</div>
\ No newline at end of file
+ <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>
\ No newline at end of file
-<div class="container{{ $booksViewType === 'list' ? ' small' : '' }}">
- <h1>{{ trans('entities.books') }}</h1>
+<div class="content-wrap mt-m card">
+ <div class="grid half v-center">
+ <h1 class="list-heading">{{ trans('entities.books') }}</h1>
+ <div class="text-right">
+
+ @include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'books'])
+
+ </div>
+ </div>
@if(count($books) > 0)
- @if($booksViewType === 'list')
- @foreach($books as $book)
- @include('books/list-item', ['book' => $book])
- <hr>
- @endforeach
- {!! $books->render() !!}
+ @if($view === 'list')
+ <div class="entity-list">
+ @foreach($books as $book)
+ @include('books.list-item', ['book' => $book])
+ @endforeach
+ </div>
@else
<div class="grid third">
@foreach($books as $key => $book)
- @include('books/grid-item', ['book' => $book])
+ @include('books.grid-item', ['book' => $book])
@endforeach
</div>
- <div>
- {!! $books->render() !!}
- </div>
@endif
+ <div>
+ {!! $books->render() !!}
+ </div>
@else
<p class="text-muted">{{ trans('entities.books_empty') }}</p>
@if(userCan('books-create-all'))
--- /dev/null
+@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
+++ /dev/null
-@extends('simple-layout')
-
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('books._breadcrumbs', ['book' => $book])
- </div>
-@stop
-
-@section('body')
-
- <div class="container">
- <p> </p>
- <div class="card">
- <h3>@icon('lock') {{ trans('entities.books_permissions') }}</h3>
- <div class="body">
- @include('form/restriction-form', ['model' => $book])
- </div>
- </div>
- </div>
-
-@stop
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-sm-6 col-xs-1 faded">
- @include('books._breadcrumbs', ['book' => $book])
+@section('container-attrs')
+ id="entity-dashboard"
+ entity-id="{{ $book->id }}"
+ entity-type="book"
+@stop
+
+@section('body')
+
+ <div class="mb-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ ]])
</div>
- <div class="col-sm-6 col-xs-11">
- <div class="action-buttons faded">
- <span dropdown class="dropdown-container">
- <div dropdown-toggle class="text-button text-primary">@icon('export'){{ trans('entities.export') }}</div>
- <ul class="wide">
- <li><a href="{{ $book->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
- <li><a href="{{ $book->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
- <li><a href="{{ $book->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
- </ul>
- </span>
- @if(userCan('page-create', $book))
- <a href="{{ $book->getUrl('/create-page') }}" class="text-pos text-button">@icon('add'){{ trans('entities.pages_new') }}</a>
- @endif
- @if(userCan('chapter-create', $book))
- <a href="{{ $book->getUrl('/create-chapter') }}" class="text-pos text-button">@icon('add'){{ trans('entities.chapters_new') }}</a>
- @endif
- @if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book))
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('more'){{ trans('common.more') }}</a>
- <ul>
- @if(userCan('book-update', $book))
- <li><a href="{{ $book->getUrl('/edit') }}" class="text-primary">@icon('edit'){{ trans('common.edit') }}</a></li>
- <li><a href="{{ $book->getUrl('/sort') }}" class="text-primary">@icon('sort'){{ trans('common.sort') }}</a></li>
+
+ <div class="content-wrap card">
+ <h1 class="break-text" v-pre>{{$book->name}}</h1>
+ <div class="book-content" v-show="!searching">
+ <p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p>
+ @if(count($bookChildren) > 0)
+ <div class="entity-list book-contents" v-pre>
+ @foreach($bookChildren as $childElement)
+ @if($childElement->isA('chapter'))
+ @include('chapters.list-item', ['chapter' => $childElement])
+ @else
+ @include('pages.list-item', ['page' => $childElement])
@endif
- @if(userCan('restrictions-manage', $book))
- <li><a href="{{ $book->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li>
+ @endforeach
+ </div>
+ @else
+ <div class="mt-xl" v-pre>
+ <hr>
+ <p class="text-muted italic mb-m mt-xl">{{ trans('entities.books_empty_contents') }}</p>
+
+ <div class="icon-list block inline">
+ @if(userCan('page-create', $book))
+ <a href="{{ $book->getUrl('/create-page') }}" class="icon-list-item text-page">
+ <span class="icon">@icon('page')</span>
+ <span>{{ trans('entities.books_empty_create_page') }}</span>
+ </a>
@endif
- @if(userCan('book-delete', $book))
- <li><a href="{{ $book->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li>
+ @if(userCan('chapter-create', $book))
+ <a href="{{ $book->getUrl('/create-chapter') }}" class="icon-list-item text-chapter">
+ <span class="icon">@icon('chapter')</span>
+ <span>{{ trans('entities.books_empty_add_chapter') }}</span>
+ </a>
@endif
- </ul>
+ </div>
+
</div>
@endif
</div>
+
+ @include('partials.entity-dashboard-search-results')
</div>
-@stop
-@section('sidebar')
+@stop
- @if($book->tags->count() > 0)
- <section>
- @include('components.tag-list', ['entity' => $book])
- </section>
- @endif
- <div class="card">
- <div class="body">
- <form v-on:submit.prevent="searchBook" class="search-box">
- <input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}">
- <button type="submit">@icon('search')</button>
- <button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button">@icon('close')</button>
- </form>
- </div>
- </div>
+@section('right')
- <div class="card entity-details">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
- <div class="body text-small text-muted blended-links">
+ <div class="mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
+ <div class="text-small text-muted blended-links">
@include('partials.entity-meta', ['entity' => $book])
@if($book->restricted)
<div class="active-restriction">
</div>
</div>
- @if(count($activity) > 0)
- <div class="activity card">
- <h3>@icon('time') {{ trans('entities.recent_activity') }}</h3>
- @include('partials/activity-list', ['activity' => $activity])
- </div>
- @endif
-@stop
-@section('container-attrs')
- id="entity-dashboard"
- entity-id="{{ $book->id }}"
- entity-type="book"
-@stop
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
-@section('body')
+ @if(userCan('page-create', $book))
+ <a href="{{ $book->getUrl('/create-page') }}" class="icon-list-item">
+ <span>@icon('add')</span>
+ <span>{{ trans('entities.pages_new') }}</span>
+ </a>
+ @endif
+ @if(userCan('chapter-create', $book))
+ <a href="{{ $book->getUrl('/create-chapter') }}" class="icon-list-item">
+ <span>@icon('add')</span>
+ <span>{{ trans('entities.chapters_new') }}</span>
+ </a>
+ @endif
- <div class="container small nopad">
- <h1 class="break-text" v-pre>{{$book->name}}</h1>
- <div class="book-content" v-show="!searching">
- <p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p>
- @if(count($bookChildren) > 0)
- <div class="page-list" v-pre>
- <hr>
- @foreach($bookChildren as $childElement)
- @if($childElement->isA('chapter'))
- @include('chapters/list-item', ['chapter' => $childElement])
- @else
- @include('pages/list-item', ['page' => $childElement])
- @endif
- <hr>
- @endforeach
- </div>
- @else
- <div class="well">
- <p class="text-muted italic">{{ trans('entities.books_empty_contents') }}</p>
- @if(userCan('page-create', $book))
- <a href="{{ $book->getUrl('/create-page') }}" class="button outline page">@icon('page'){{ trans('entities.books_empty_create_page') }}</a>
- @endif
- @if(userCan('page-create', $book) && userCan('chapter-create', $book))
- <em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>
- @endif
- @if(userCan('chapter-create', $book))
- <a href="{{ $book->getUrl('/create-chapter') }}" class="button outline chapter">@icon('chapter'){{ trans('entities.books_empty_add_chapter') }}</a>
- @endif
- </div>
+ <hr class="primary-background">
+
+ @if(userCan('book-update', $book))
+ <a href="{{ $book->getUrl('/edit') }}" class="icon-list-item">
+ <span>@icon('edit')</span>
+ <span>{{ trans('common.edit') }}</span>
+ </a>
+ <a href="{{ $book->getUrl('/sort') }}" class="icon-list-item">
+ <span>@icon('sort')</span>
+ <span>{{ trans('common.sort') }}</span>
+ </a>
+ @endif
+ @if(userCan('restrictions-manage', $book))
+ <a href="{{ $book->getUrl('/permissions') }}" class="icon-list-item">
+ <span>@icon('lock')</span>
+ <span>{{ trans('entities.permissions') }}</span>
+ </a>
+ @endif
+ @if(userCan('book-delete', $book))
+ <a href="{{ $book->getUrl('/delete') }}" class="icon-list-item">
+ <span>@icon('delete')</span>
+ <span>{{ trans('common.delete') }}</span>
+ </a>
@endif
- </div>
- <div class="search-results" v-cloak v-show="searching">
- <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small">@icon('close'){{ trans('entities.search_clear') }}</a></h3>
- <div v-if="!searchResults">
- @include('partials/loading-icon')
+ <hr class="primary-background">
+
+ <div dropdown class="dropdown-container">
+ <div dropdown-toggle class="icon-list-item">
+ <span>@icon('export')</span>
+ <span>{{ trans('entities.export') }}</span>
+ </div>
+ <ul class="wide">
+ <li><a href="{{ $book->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
+ <li><a href="{{ $book->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
+ <li><a href="{{ $book->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
+ </ul>
</div>
- <div v-html="searchResults"></div>
</div>
</div>
@stop
+
+@section('left')
+
+ @include('partials.entity-dashboard-search-box')
+
+ @if($book->tags->count() > 0)
+ <div class="mb-xl">
+ @include('components.tag-list', ['entity' => $book])
+ </div>
+ @endif
+
+ @if(count($activity) > 0)
+ <div class="mb-xl">
+ <h5>{{ trans('entities.recent_activity') }}</h5>
+ @include('partials.activity-list', ['activity' => $activity])
+ </div>
+ @endif
+@stop
+
<div class="sort-box" data-type="book" data-id="{{ $book->id }}">
- <h3 class="text-book">@icon('book'){{ $book->name }}</h3>
+ <h5 class="text-book entity-list-item no-hover py-xs pl-none">
+ <span>@icon('book')</span>
+ <span>{{ $book->name }}</span>
+ </h5>
+ <div class="sort-box-options pb-sm">
+ <a href="#" data-sort="name" class="button outline small">{{ trans('entities.books_sort_name') }}</a>
+ <a href="#" data-sort="created" class="button outline small">{{ trans('entities.books_sort_created') }}</a>
+ <a href="#" data-sort="updated" class="button outline small">{{ trans('entities.books_sort_updated') }}</a>
+ <a href="#" data-sort="chaptersFirst" class="button outline small">{{ trans('entities.books_sort_chapters_first') }}</a>
+ <a href="#" data-sort="chaptersLast" class="button outline small">{{ trans('entities.books_sort_chapters_last') }}</a>
+ </div>
<ul class="sortable-page-list sort-list">
+
@foreach($bookChildren as $bookChild)
- <li data-id="{{$bookChild->id}}" data-type="{{ $bookChild->getClassName() }}" class="text-{{ $bookChild->getClassName() }}">
- @icon($bookChild->isA('chapter') ? 'chapter' : 'page'){{ $bookChild->name }}
+ <li class="text-{{ $bookChild->getClassName() }}"
+ data-id="{{$bookChild->id}}" data-type="{{ $bookChild->getClassName() }}"
+ data-name="{{ $bookChild->name }}" data-created="{{ $bookChild->created_at->timestamp }}"
+ data-updated="{{ $bookChild->updated_at->timestamp }}">
+ <div class="entity-list-item">
+ <span>@icon($bookChild->getType()) </span>
+ <div>
+ {{ $bookChild->name }}
+ <div>
+
+ </div>
+ </div>
+ </div>
@if($bookChild->isA('chapter'))
<ul>
@foreach($bookChild->pages as $page)
- <li data-id="{{$page->id}}" class="text-page" data-type="page">
- @icon('page')
- {{ $page->name }}
+ <li class="text-page"
+ data-id="{{$page->id}}" data-type="page"
+ data-name="{{ $page->name }}" data-created="{{ $page->created_at->timestamp }}"
+ data-updated="{{ $page->updated_at->timestamp }}">
+ <div class="entity-list-item">
+ <span>@icon('page')</span>
+ <span>{{ $page->name }}</span>
+ </div>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
+
</ul>
</div>
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('books._breadcrumbs', ['book' => $book])
- </div>
-@stop
-
@section('body')
<div class="container">
- <div class="row">
- <div class="col-md-8">
- <div class="card">
- <h3>@icon('sort') {{ trans('entities.books_sort') }}</h3>
- <div class="body">
- <div id="sort-boxes">
- @include('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
- </div>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ $book->getUrl('/sort') => [
+ 'text' => trans('entities.books_sort'),
+ 'icon' => 'sort',
+ ]
+ ]])
+ </div>
- <form action="{{ $book->getUrl('/sort') }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="PUT">
- <input type="hidden" id="sort-tree-input" name="sort-tree">
- <div class="list">
- <a href="{{ $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button class="button pos" type="submit">{{ trans('entities.books_sort_save') }}</button>
- </div>
- </form>
+ <div class="grid left-focus gap-xl">
+ <div>
+ <div class="card content-wrap">
+ <h1 class="list-heading mb-l">{{ trans('entities.books_sort') }}</h1>
+ <div id="sort-boxes">
+ @include('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
</div>
+
+ <form action="{{ $book->getUrl('/sort') }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
+ <input type="hidden" id="sort-tree-input" name="sort-tree">
+ <div class="list text-right">
+ <a href="{{ $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button class="button primary" type="submit">{{ trans('entities.books_sort_save') }}</button>
+ </div>
+ </form>
</div>
</div>
- @if(count($books) > 1)
- <div class="col-md-4">
- <div class="card">
- <h3>@icon('book') {{ trans('entities.books_sort_show_other') }}</h3>
- <div class="body" id="additional-books">
- @foreach($books as $otherBook)
- @if($otherBook->id !== $book->id)
- <div>
- <a href="{{ $otherBook->getUrl('/sort-item') }}" class="text-book">@icon('book'){{ $otherBook->name }}</a>
- </div>
- @endif
- @endforeach
- </div>
+
+ <div>
+ <div class="card content-wrap">
+ <h2 class="list-heading mb-m">{{ trans('entities.books_sort_show_other') }}</h2>
+
+ @include('components.entity-selector', ['name' => 'books_list', 'selectorSize' => 'compact', 'entityTypes' => 'book', 'entityPermission' => 'update', 'showAdd' => true])
+
</div>
</div>
- @endif
</div>
+
</div>
@stop
<script>
$(document).ready(function() {
- var sortableOptions = {
+ const $container = $('#sort-boxes');
+
+ // Sortable options
+ const sortableOptions = {
group: 'serialization',
- onDrop: function($item, container, _super) {
- var pageMap = buildEntityMap();
- $('#sort-tree-input').val(JSON.stringify(pageMap));
+ containerSelector: 'ul',
+ itemPath: '',
+ itemSelector: 'li',
+ onDrop: function ($item, container, _super) {
+ updateMapInput();
_super($item, container);
},
- isValidTarget: function ($item, container) {
+ isValidTarget: function ($item, container) {
// Prevent nested chapters
- return !($item.is('[data-type="chapter"]') && container.target.closest('li').attr('data-type') == 'chapter');
+ return !($item.is('[data-type="chapter"]') && container.target.closest('li').attr('data-type') === 'chapter');
}
};
- var group = $('.sort-list').sortable(sortableOptions);
+ // Create our sortable group
+ let group = $('.sort-list').sortable(sortableOptions);
- $('#additional-books').on('click', 'a', function(e) {
- e.preventDefault();
- var $link = $(this);
- var url = $link.attr('href');
- $.get(url, function(data) {
- $('#sort-boxes').append(data);
+ // Add book on selection confirm
+ window.$events.listen('entity-select-confirm', function(entityInfo) {
+ const alreadyAdded = $container.find(`[data-type="book"][data-id="${entityInfo.id}"]`).length > 0;
+ if (alreadyAdded) return;
+
+ const entitySortItemUrl = entityInfo.link + '/sort-item';
+ window.$http.get(entitySortItemUrl).then(resp => {
+ $container.append(resp.data);
group.sortable("destroy");
- $('.sort-list').sortable(sortableOptions);
+ group = $('.sort-list').sortable(sortableOptions);
});
- $link.remove();
});
+ /**
+ * Update the input with our sort data.
+ */
+ function updateMapInput() {
+ const pageMap = buildEntityMap();
+ $('#sort-tree-input').val(JSON.stringify(pageMap));
+ }
+
/**
* Build up a mapping of entities with their ordering and nesting.
* @returns {Array}
*/
function buildEntityMap() {
- var entityMap = [];
- var $lists = $('.sort-list');
+ const entityMap = [];
+ const $lists = $('.sort-list');
$lists.each(function(listIndex) {
- var list = $(this);
- var bookId = list.closest('[data-type="book"]').attr('data-id');
- var $directChildren = list.find('> [data-type="page"], > [data-type="chapter"]');
+ const $list = $(this);
+ const bookId = $list.closest('[data-type="book"]').attr('data-id');
+ const $directChildren = $list.find('> [data-type="page"], > [data-type="chapter"]');
$directChildren.each(function(directChildIndex) {
- var $childElem = $(this);
- var type = $childElem.attr('data-type');
- var parentChapter = false;
- var childId = $childElem.attr('data-id');
+ const $childElem = $(this);
+ const type = $childElem.attr('data-type');
+ const parentChapter = false;
+ const childId = $childElem.attr('data-id');
+
entityMap.push({
id: childId,
sort: directChildIndex,
type: type,
book: bookId
});
- $chapterChildren = $childElem.find('[data-type="page"]').each(function(pageIndex) {
- var $chapterChild = $(this);
+
+ $childElem.find('[data-type="page"]').each(function(pageIndex) {
+ const $chapterChild = $(this);
entityMap.push({
id: $chapterChild.attr('data-id'),
sort: pageIndex,
book: bookId
});
});
+
});
});
return entityMap;
}
+
+ // Auto sort control
+ const sortOperations = {
+ name: function(a, b) {
+ const aName = a.getAttribute('data-name').trim().toLowerCase();
+ const bName = b.getAttribute('data-name').trim().toLowerCase();
+ return aName.localeCompare(bName);
+ },
+ created: function(a, b) {
+ const aTime = Number(a.getAttribute('data-created'));
+ const bTime = Number(b.getAttribute('data-created'));
+ return bTime - aTime;
+ },
+ updated: function(a, b) {
+ const aTime = Number(a.getAttribute('data-update'));
+ const bTime = Number(b.getAttribute('data-update'));
+ return bTime - aTime;
+ },
+ chaptersFirst: function(a, b) {
+ const aType = a.getAttribute('data-type');
+ const bType = b.getAttribute('data-type');
+ if (aType === bType) {
+ return 0;
+ }
+ return (aType === 'chapter' ? -1 : 1);
+ },
+ chaptersLast: function(a, b) {
+ const aType = a.getAttribute('data-type');
+ const bType = b.getAttribute('data-type');
+ if (aType === bType) {
+ return 0;
+ }
+ return (aType === 'chapter' ? 1 : -1);
+ },
+ };
+
+ let lastSort = '';
+ let reverse = false;
+ const reversibleTypes = ['name', 'created', 'updated'];
+
+ $container.on('click', '.sort-box-options [data-sort]', function(event) {
+ event.preventDefault();
+ const $sortLists = $(this).closest('.sort-box').find('ul');
+ const sort = $(this).attr('data-sort');
+
+ reverse = (lastSort === sort) ? !reverse : false;
+ let sortFunction = sortOperations[sort];
+ if (reverse && reversibleTypes.includes(sort)) {
+ sortFunction = function(a, b) {
+ return 0 - sortOperations[sort](a, b)
+ };
+ }
+
+ $sortLists.each(function() {
+ const $list = $(this);
+ $list.children('li').sort(sortFunction).appendTo($list);
+ });
+
+ lastSort = sort;
+ updateMapInput();
+ });
+
});
</script>
@stop
+++ /dev/null
-<form action="{{ baseUrl("/settings/users/{$currentUser->id}/switch-book-view") }}" method="POST" class="inline">
- {!! csrf_field() !!}
- {!! method_field('PATCH') !!}
- <input type="hidden" value="{{ $booksViewType === 'list'? 'grid' : 'list' }}" name="view_type">
- @if ($booksViewType === 'list')
- <button type="submit" class="text-pos text-button">@icon('grid'){{ trans('common.grid_view') }}</button>
- @else
- <button type="submit" class="text-pos text-button">@icon('list'){{ trans('common.list_view') }}</button>
- @endif
-</form>
\ No newline at end of file
+++ /dev/null
-<div class="breadcrumbs">
- @if (userCan('view', $chapter->book))
- <a href="{{ $chapter->book->getUrl() }}" class="text-book text-button">@icon('book'){{ $chapter->book->getShortName() }}</a>
- <span class="sep">»</span>
- @endif
- <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button">@icon('chapter'){{$chapter->getShortName()}}</a>
-</div>
\ No newline at end of file
--- /dev/null
+<div class="chapter-child-menu">
+ <p chapter-toggle class="text-muted @if($bookChild->matchesOrContains($current)) open @endif">
+ @icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $bookChild->pages->count()) }}</span>
+ </p>
+ <ul class="sub-menu inset-list @if($bookChild->matchesOrContains($current)) open @endif">
+ @foreach($bookChild->pages as $childPage)
+ <li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}">
+ @include('partials.entity-list-item-basic', ['entity' => $childPage, 'classes' => $current->matches($childPage)? 'selected' : '' ])
+ </li>
+ @endforeach
+ </ul>
+</div>
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- <div class="breadcrumbs">
- <a href="{{ $book->getUrl() }}" class="text-book text-button">@icon('book'){{ $book->getShortName() }}</a>
- <span class="sep">»</span>
- <a href="{{ $book->getUrl('/create-chapter')}}" class="text-button">@icon('add'){{ trans('entities.chapters_create') }}</a>
- </div>
- </div>
-@stop
-
@section('body')
-
<div class="container small">
- <div class="card">
- <h3>@icon('add') {{ trans('entities.chapters_create') }}</h3>
- <div class="body">
- <form action="{{ $book->getUrl('/create-chapter') }}" method="POST">
- @include('chapters/form')
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ $book->getUrl('create-chapter') => [
+ 'text' => trans('entities.chapters_create'),
+ 'icon' => 'add',
+ ]
+ ]])
+ </div>
+
+ <div class="content-wrap card">
+ <h1 class="list-heading">{{ trans('entities.chapters_create') }}</h1>
+ <form action="{{ $book->getUrl('/create-chapter') }}" method="POST">
+ @include('chapters.form')
+ </form>
</div>
- </div>
+ </div>
@stop
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('chapters._breadcrumbs', ['chapter' => $chapter])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ trans('entities.chapters_delete') }}</h3>
- <div class="body">
- <p>{{ trans('entities.chapters_delete_explain', ['chapterName' => $chapter->name]) }}</p>
- <p class="text-neg">{{ trans('entities.chapters_delete_confirm') }}</p>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $chapter->book,
+ $chapter,
+ $chapter->getUrl('/delete') => [
+ 'text' => trans('entities.chapters_delete'),
+ 'icon' => 'delete',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('entities.chapters_delete') }}</h1>
+ <p>{{ trans('entities.chapters_delete_explain', ['chapterName' => $chapter->name]) }}</p>
+ <p class="text-neg"><strong>{{ trans('entities.chapters_delete_confirm') }}</strong></p>
+
+ <form action="{{ $chapter->getUrl() }}" method="POST">
+
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
- <form action="{{ $chapter->getUrl() }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
+ <div class="text-right">
<a href="{{ $chapter->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
- </form>
- </div>
+ <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
+ </div>
+ </form>
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('chapters._breadcrumbs', ['chapter' => $chapter])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('edit') {{ trans('entities.chapters_edit') }}</h3>
- <div class="body">
- <form action="{{ $chapter->getUrl() }}" method="POST">
- <input type="hidden" name="_method" value="PUT">
- @include('chapters/form', ['model' => $chapter])
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $book,
+ $chapter,
+ $chapter->getUrl('/edit') => [
+ 'text' => trans('entities.chapters_edit'),
+ 'icon' => 'edit'
+ ]
+ ]])
</div>
+
+ <div class="content-wrap card">
+ <h1 class="list-heading">{{ trans('entities.chapters_edit') }}</h1>
+ <form action="{{ $chapter->getUrl() }}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('chapters.form', ['model' => $chapter])
+ </form>
+ </div>
+
</div>
@stop
\ No newline at end of file
@include('partials.custom-head')
</head>
<body>
-<div class="container">
- <div class="row">
- <div class="col-md-8 col-md-offset-2">
- <div class="page-content">
-
- <h1 style="font-size: 4.8em">{{$chapter->name}}</h1>
-
- <p>{{ $chapter->description }}</p>
-
- @if(count($pages) > 0)
- <ul class="contents">
- @foreach($pages as $page)
- <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
- @endforeach
- </ul>
- @endif
-
- @foreach($pages as $page)
- <div class="page-break"></div>
- <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
- {!! $page->html !!}
- @endforeach
-
- </div>
- </div>
- </div>
+
+<div class="page-content">
+
+ <h1 style="font-size: 4.8em">{{$chapter->name}}</h1>
+
+ <p>{{ $chapter->description }}</p>
+
+ @if(count($pages) > 0)
+ <ul class="contents">
+ @foreach($pages as $page)
+ <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
+ @endforeach
+ </ul>
+ @endif
+
+ @foreach($pages as $page)
+ <div class="page-break"></div>
+ <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
+ {!! $page->html !!}
+ @endforeach
+
</div>
+
</body>
</html>
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>
- @include('form/text', ['name' => 'name'])
+ @include('form.text', ['name' => 'name'])
</div>
<div class="form-group description-input">
<label for="description">{{ trans('common.description') }}</label>
- @include('form/textarea', ['name' => 'description'])
+ @include('form.textarea', ['name' => 'description'])
</div>
<div class="form-group" collapsible id="logo-control">
<div class="form-group text-right">
<a href="{{ isset($chapter) ? $chapter->getUrl() : $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.chapters_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('entities.chapters_save') }}</button>
</div>
-<div class="chapter entity-list-item" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
- <h4>
- @if (isset($showPath) && $showPath)
- <a href="{{ $chapter->book->getUrl() }}" class="text-book">
- @icon('book'){{ $chapter->book->getShortName() }}
- </a>
- <span class="text-muted"> » </span>
- @endif
- <a href="{{ $chapter->getUrl() }}" class="text-chapter entity-list-item-link">
- @icon('chapter')<span class="entity-list-item-name break-text">{{ $chapter->name }}</span>
- </a>
- </h4>
-
- <div class="entity-item-snippet">
- @if(isset($chapter->searchSnippet))
- <p class="text-muted break-text">{!! $chapter->searchSnippet !!}</p>
- @else
- <p class="text-muted break-text">{{ $chapter->getExcerpt() }}</p>
- @endif
+<a href="{{ $chapter->getUrl() }}" class="chapter entity-list-item @if($chapter->hasChildren()) has-children @endif" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
+ <span class="icon text-chapter">@icon('chapter')</span>
+ <div class="content">
+ <h4 class="entity-list-item-name break-text">{{ $chapter->name }}</h4>
+ <div class="entity-item-snippet">
+ <p class="text-muted break-text mb-s">{{ $chapter->getExcerpt() }}</p>
+ </div>
</div>
-
-
- @if(!isset($hidePages) && count($chapter->pages) > 0)
- <p chapter-toggle class="text-muted">@icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $chapter->pages->count()) }}</span></p>
- <div class="inset-list">
- @foreach($chapter->pages as $page)
- <h5 class="@if($page->draft) draft @endif"><a href="{{ $page->getUrl() }}" class="text-page @if($page->draft) draft @endif">@icon('page'){{$page->name}}</a></h5>
- @endforeach
+</a>
+@if ($chapter->hasChildren())
+ <div class="chapter chapter-expansion">
+ <span class="icon text-chapter">@icon('page')</span>
+ <div class="content">
+ <div chapter-toggle class="text-muted chapter-expansion-toggle">@icon('caret-right') <span>{{ trans_choice('entities.x_pages', $chapter->pages->count()) }}</span></div>
+ <div class="inset-list">
+ <div class="entity-list-item-children">
+ @include('partials.entity-list', ['entities' => $chapter->pages])
+ </div>
+ </div>
</div>
- @endif
-</div>
\ No newline at end of file
+ </div>
+@endif
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('chapters._breadcrumbs', ['chapter' => $chapter])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <div class="card">
- <h3>@icon('folder') {{ trans('entities.chapters_move') }}</h3>
- <div class="body">
- <form action="{{ $chapter->getUrl('/move') }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="PUT">
-
- @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book', 'entityPermission' => 'chapter-create'])
-
- <div class="form-group text-right">
- <a href="{{ $chapter->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.chapters_move') }}</button>
- </div>
- </form>
- </div>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $chapter->book,
+ $chapter,
+ $chapter->getUrl('/move') => [
+ 'text' => trans('entities.chapters_move'),
+ 'icon' => 'folder',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.chapters_move') }}</h1>
+
+ <form action="{{ $chapter->getUrl('/move') }}" method="POST">
+
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
+
+ @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book', 'entityPermission' => 'chapter-create'])
+
+ <div class="form-group text-right">
+ <a href="{{ $chapter->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('entities.chapters_move') }}</button>
+ </div>
+ </form>
+
</div>
--- /dev/null
+@extends('simple-layout')
+
+@section('body')
+
+ <div class="container">
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $chapter->book,
+ $chapter,
+ $chapter->getUrl('/permissions') => [
+ 'text' => trans('entities.chapters_permissions'),
+ 'icon' => 'lock',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.chapters_permissions') }}</h1>
+ @include('form.entity-permissions', ['model' => $chapter])
+ </div>
+ </div>
+
+@stop
+++ /dev/null
-@extends('simple-layout')
-
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('chapters._breadcrumbs', ['chapter' => $chapter])
- </div>
-@stop
-
-@section('body')
-
- <div class="container">
- <p> </p>
- <div class="card">
- <h3>@icon('lock') {{ trans('entities.chapters_permissions') }}</h3>
- <div class="body">
- @include('form/restriction-form', ['model' => $chapter])
- </div>
- </div>
- </div>
-
-@stop
-@extends('sidebar-layout')
-
-@section('toolbar')
- <div class="col-sm-6 col-xs-3 faded" v-pre>
- @include('chapters._breadcrumbs', ['chapter' => $chapter])
- </div>
- <div class="col-sm-6 col-xs-9 faded">
- <div class="action-buttons">
- <span dropdown class="dropdown-container">
- <div dropdown-toggle class="text-button text-primary">@icon('export'){{ trans('entities.export') }}</div>
- <ul class="wide">
- <li><a href="{{ $chapter->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
- <li><a href="{{ $chapter->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
- <li><a href="{{ $chapter->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
- </ul>
- </span>
- @if(userCan('page-create', $chapter))
- <a href="{{ $chapter->getUrl('/create-page') }}" class="text-pos text-button">@icon('add'){{ trans('entities.pages_new') }}</a>
- @endif
- @if(userCan('chapter-update', $chapter))
- <a href="{{ $chapter->getUrl('/edit') }}" class="text-primary text-button">@icon('edit'){{ trans('common.edit') }}</a>
- @endif
- @if((userCan('chapter-update', $chapter) && userCan('chapter-delete', $chapter) )|| userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter))
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('more') {{ trans('common.more') }}</a>
- <ul>
- @if(userCan('chapter-update', $chapter) && userCan('chapter-delete', $chapter))
- <li><a href="{{ $chapter->getUrl('/move') }}" class="text-primary">@icon('folder'){{ trans('common.move') }}</a></li>
- @endif
- @if(userCan('restrictions-manage', $chapter))
- <li><a href="{{ $chapter->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li>
- @endif
- @if(userCan('chapter-delete', $chapter))
- <li><a href="{{ $chapter->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li>
- @endif
- </ul>
- </div>
- @endif
- </div>
- </div>
-@stop
+@extends('tri-layout')
@section('container-attrs')
id="entity-dashboard"
entity-type="chapter"
@stop
-@section('sidebar')
+@section('body')
- @if($chapter->tags->count() > 0)
- <section>
- @include('components.tag-list', ['entity' => $chapter])
- </section>
- @endif
+ <div class="mb-m">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $chapter->book,
+ $chapter,
+ ]])
+ </div>
- <div class="card">
- <div class="body">
- <form @submit.prevent="searchBook" class="search-box">
- <input v-model="searchTerm" @change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.chapters_search_this') }}">
- <button type="submit">@icon('search')</button>
- <button v-if="searching" v-cloak class="text-neg" @click="clearSearch()" type="button">@icon('close')</button>
- </form>
+ <div class="content-wrap card">
+ <h1 class="break-text" v-pre>{{ $chapter->name }}</h1>
+ <div class="chapter-content" v-show="!searching">
+ <p v-pre class="text-muted break-text">{!! nl2br(e($chapter->description)) !!}</p>
+ @if(count($pages) > 0)
+ <div v-pre class="entity-list book-contents">
+ @foreach($pages as $page)
+ @include('pages.list-item', ['page' => $page])
+ @endforeach
+ </div>
+ @else
+ <div class="mt-xl" v-pre>
+ <hr>
+ <p class="text-muted italic mb-m mt-xl">{{ trans('entities.chapters_empty') }}</p>
+
+ <div class="icon-list block inline">
+ @if(userCan('page-create', $chapter))
+ <a href="{{ $chapter->getUrl('/create-page') }}" class="icon-list-item text-page">
+ <span class="icon">@icon('page')</span>
+ <span>{{ trans('entities.books_empty_create_page') }}</span>
+ </a>
+ @endif
+ @if(userCan('book-update', $book))
+ <a href="{{ $book->getUrl('/sort') }}" class="icon-list-item text-book">
+ <span class="icon">@icon('book')</span>
+ <span>{{ trans('entities.books_empty_sort_current_book') }}</span>
+ </a>
+ @endif
+ </div>
+
+ </div>
+ @endif
</div>
+
+ @include('partials.entity-dashboard-search-results')
</div>
- <div class="card entity-details">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
- <div class="body blended-links text-small text-muted">
+@stop
+
+@section('right')
+
+ <div class="mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
+ <div class="blended-links text-small text-muted">
@include('partials.entity-meta', ['entity' => $chapter])
@if($book->restricted)
</div>
</div>
- @include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
-@stop
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
-@section('body')
+ @if(userCan('page-create', $chapter))
+ <a href="{{ $chapter->getUrl('/create-page') }}" class="icon-list-item">
+ <span>@icon('add')</span>
+ <span>{{ trans('entities.pages_new') }}</span>
+ </a>
+ @endif
- <div class="container small nopad">
- <h1 class="break-text" v-pre>{{ $chapter->name }}</h1>
- <div class="chapter-content" v-show="!searching">
- <p v-pre class="text-muted break-text">{!! nl2br(e($chapter->description)) !!}</p>
+ <hr class="primary-background"/>
- @if(count($pages) > 0)
- <div v-pre class="page-list">
- <hr>
- @foreach($pages as $page)
- @include('pages/list-item', ['page' => $page])
- <hr>
- @endforeach
- </div>
- @else
- <div v-pre class="well">
- <p class="text-muted italic">{{ trans('entities.chapters_empty') }}</p>
- <p>
- @if(userCan('page-create', $chapter))
- <a href="{{ $chapter->getUrl('/create-page') }}" class="button outline page">@icon('page'){{ trans('entities.books_empty_create_page') }}</a>
- @endif
- @if(userCan('page-create', $chapter) && userCan('book-update', $book))
- <em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>
- @endif
- @if(userCan('book-update', $book))
- <a href="{{ $book->getUrl('/sort') }}" class="button outline book">@icon('book'){{ trans('entities.books_empty_sort_current_book') }}</a>
- @endif
- </p>
- </div>
+ @if(userCan('chapter-update', $chapter))
+ <a href="{{ $chapter->getUrl('/edit') }}" class="icon-list-item">
+ <span>@icon('edit')</span>
+ <span>{{ trans('common.edit') }}</span>
+ </a>
@endif
- </div>
+ @if(userCan('chapter-update', $chapter) && userCan('chapter-delete', $chapter))
+ <a href="{{ $chapter->getUrl('/move') }}" class="icon-list-item">
+ <span>@icon('folder')</span>
+ <span>{{ trans('common.move') }}</span>
+ </a>
+ @endif
+ @if(userCan('restrictions-manage', $chapter))
+ <a href="{{ $chapter->getUrl('/permissions') }}" class="icon-list-item">
+ <span>@icon('lock')</span>
+ <span>{{ trans('entities.permissions') }}</span>
+ </a>
+ @endif
+ @if(userCan('chapter-delete', $chapter))
+ <a href="{{ $chapter->getUrl('/delete') }}" class="icon-list-item">
+ <span>@icon('delete')</span>
+ <span>{{ trans('common.delete') }}</span>
+ </a>
+ @endif
+
+ <hr class="primary-background"/>
- <div class="search-results" v-cloak v-show="searching">
- <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" @click="clearSearch()" class="text-small">@icon('close'){{ trans('entities.search_clear') }}</a></h3>
- <div v-if="!searchResults">
- @include('partials/loading-icon')
+ <div dropdown class="dropdown-container">
+ <div dropdown-toggle class="icon-list-item">
+ <span>@icon('export')</span>
+ <span>{{ trans('entities.export') }}</span>
+ </div>
+ <ul class="wide">
+ <li><a href="{{ $chapter->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
+ <li><a href="{{ $chapter->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
+ <li><a href="{{ $chapter->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
+ </ul>
</div>
- <div v-html="searchResults"></div>
</div>
</div>
+@stop
+
+@section('left')
+
+ @include('partials.entity-dashboard-search-box')
+
+ @if($chapter->tags->count() > 0)
+ <div class="mb-xl">
+ @include('components.tag-list', ['entity' => $chapter])
+ </div>
+ @endif
+ @include('partials.book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
@stop
+
+
-<div class="comment-box" comment="{{ $comment->id }}" local-id="{{$comment->local_id}}" parent-id="{{$comment->parent_id}}" id="comment{{$comment->local_id}}">
- <div class="header">
-
- <div class="float right actions">
- @if(userCan('comment-update', $comment))
- <button type="button" class="text-button" action="edit" title="{{ trans('common.edit') }}">@icon('edit')</button>
- @endif
- @if(userCan('comment-create-all'))
- <button type="button" class="text-button" action="reply" title="{{ trans('common.reply') }}">@icon('reply')</button>
- @endif
- @if(userCan('comment-delete', $comment))
-
- <div dropdown class="dropdown-container">
- <button type="button" dropdown-toggle class="text-button" title="{{ trans('common.delete') }}">@icon('delete')</button>
- <ul>
- <li class="padded"><small class="text-muted">{{trans('entities.comment_delete_confirm')}}</small></li>
- <li><a action="delete" class="text-button neg" >@icon('delete'){{ trans('common.delete') }}</a></li>
- </ul>
- </div>
- @endif
- </div>
-
- <div class="meta">
- <a href="#comment{{$comment->local_id}}" class="text-muted">#{{$comment->local_id}}</a>
-
- @if ($comment->createdBy)
- <img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar" alt="{{ $comment->createdBy->name }}">
-
- <a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->name }}</a>
- @else
- <span>{{ trans('common.deleted_user') }}</span>
- @endif
- <span title="{{ $comment->created_at }}">
- {{ trans('entities.comment_created', ['createDiff' => $comment->created]) }}
- </span>
- @if($comment->isUpdated())
- <span title="{{ $comment->updated_at }}">
+<div class="comment-box mb-m" comment="{{ $comment->id }}" local-id="{{$comment->local_id}}" parent-id="{{$comment->parent_id}}" id="comment{{$comment->local_id}}">
+ <div class="header p-s">
+ <div class="grid half no-gap v-center">
+ <div class="meta">
+ <a href="#comment{{$comment->local_id}}" class="text-muted">#{{$comment->local_id}}</a>
+
+ @if ($comment->createdBy)
+ <img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar" alt="{{ $comment->createdBy->name }}">
+
+ <a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->name }}</a>
+ @else
+ <span>{{ trans('common.deleted_user') }}</span>
+ @endif
+ <span title="{{ $comment->created_at }}">{{ trans('entities.comment_created', ['createDiff' => $comment->created]) }}</span>
+ @if($comment->isUpdated())
+ <span title="{{ $comment->updated_at }}">
•
{{ trans('entities.comment_updated', ['updateDiff' => $comment->updated, 'username' => $comment->updatedBy? $comment->updatedBy->name : trans('common.deleted_user')]) }}
</span>
- @endif
+ @endif
+ </div>
+ <div class="actions text-right">
+ @if(userCan('comment-update', $comment))
+ <button type="button" class="text-button" action="edit" title="{{ trans('common.edit') }}">@icon('edit')</button>
+ @endif
+ @if(userCan('comment-create-all'))
+ <button type="button" class="text-button" action="reply" title="{{ trans('common.reply') }}">@icon('reply')</button>
+ @endif
+ @if(userCan('comment-delete', $comment))
+ <div dropdown class="dropdown-container">
+ <button type="button" dropdown-toggle class="text-button" title="{{ trans('common.delete') }}">@icon('delete')</button>
+ <ul>
+ <li class="px-m text-small text-muted pb-s">{{trans('entities.comment_delete_confirm')}}</li>
+ <li><a action="delete" class="text-button text-neg" >@icon('delete'){{ trans('common.delete') }}</a></li>
+ </ul>
+ </div>
+ @endif
+ </div>
</div>
</div>
@if ($comment->parent_id)
- <div class="reply-row primary-background-light text-muted">
+ <div class="reply-row primary-background-light text-muted px-s py-xs mb-s">
{!! trans('entities.comment_in_reply_to', ['commentId' => '<a href="#comment'.$comment->parent_id.'">#'.$comment->parent_id.'</a>']) !!}
</div>
@endif
- <div comment-content class="content">
+ <div comment-content class="content px-s pb-s">
<div class="form-group loading" style="display: none;">
@include('partials.loading-icon', ['text' => trans('entities.comment_deleting')])
</div>
</div>
@if(userCan('comment-update', $comment))
- <div comment-edit-container style="display: none;" class="content">
+ <div comment-edit-container style="display: none;" class="content px-s">
<form novalidate>
- <div class="form-group">
- <textarea name="markdown" rows="3" v-model="comment.text" placeholder="{{ trans('entities.comment_placeholder') }}">{{ $comment->text }}</textarea>
+ <div class="form-group description-input">
+ <textarea name="markdown" rows="3" placeholder="{{ trans('entities.comment_placeholder') }}">{{ $comment->text }}</textarea>
</div>
<div class="form-group text-right">
<button type="button" class="button outline" action="closeUpdateForm">{{ trans('common.cancel') }}</button>
- <button type="submit" class="button pos">{{ trans('entities.comment_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('entities.comment_save') }}</button>
</div>
<div class="form-group loading" style="display: none;">
@include('partials.loading-icon', ['text' => trans('entities.comment_saving')])
<div page-comments page-id="{{ $page->id }}" class="comments-list">
- <h5 comments-title class="float left">{{ trans_choice('entities.comment_count', count($page->comments), ['count' => count($page->comments)]) }}</h5>
+ <div comment-count-bar class="grid half left-focus v-center">
+ <h5 comments-title>{{ trans_choice('entities.comment_count', count($page->comments), ['count' => count($page->comments)]) }}</h5>
+ @if (count($page->comments) === 0)
+ <div class="text-right" comment-add-button-container>
+ <button type="button" action="addComment"
+ class="button outline">{{ trans('entities.comment_add') }}</button>
+ </div>
+ @endif
+ </div>
<div class="comment-container" comment-container>
@foreach($page->comments as $comment)
</div>
@if(userCan('comment-create-all'))
+ @include('comments.create')
+ @endif
- <div class="comment-box" comment-box style="display:none;">
- <div class="header">@icon('comment') {{ trans('entities.comment_new') }}</div>
- <div comment-form-reply-to class="reply-row primary-background-light text-muted" style="display: none;">
- <button class="text-button float right" action="remove-reply-to">{{ trans('common.remove') }}</button>
- {!! trans('entities.comment_in_reply_to', ['commentId' => '<a href=""></a>']) !!}
- </div>
- <div class="content" comment-form-container>
- <form novalidate>
- <div class="form-group">
- <textarea name="markdown" rows="3" v-model="comment.text" placeholder="{{ trans('entities.comment_placeholder') }}"></textarea>
- </div>
- <div class="form-group text-right">
- <button type="button" class="button outline" action="hideForm">{{ trans('common.cancel') }}</button>
- <button type="submit" class="button pos">{{ trans('entities.comment_save') }}</button>
- </div>
- <div class="form-group loading" style="display: none;">
- @include('partials.loading-icon', ['text' => trans('entities.comment_saving')])
- </div>
- </form>
- </div>
- </div>
-
- <div class="form-group" comment-add-button>
- <button type="button" action="addComment" class="button outline float right">{{ trans('entities.comment_add') }}</button>
+ @if (count($page->comments) > 0)
+ <div class="text-right" comment-add-button-container>
+ <button type="button" action="addComment"
+ class="button outline">{{ trans('entities.comment_add') }}</button>
</div>
@endif
--- /dev/null
+<div class="comment-box" comment-box style="display:none;">
+ <div class="header p-s">{{ trans('entities.comment_new') }}</div>
+ <div comment-form-reply-to class="reply-row primary-background-light text-muted px-s py-xs mb-s" style="display: none;">
+ <div class="grid left-focus v-center">
+ <div>
+ {!! trans('entities.comment_in_reply_to', ['commentId' => '<a href=""></a>']) !!}
+ </div>
+ <div class="text-right">
+ <button class="text-button" action="remove-reply-to">{{ trans('common.remove') }}</button>
+ </div>
+ </div>
+ </div>
+ <div class="content px-s" comment-form-container>
+ <form novalidate>
+ <div class="form-group description-input">
+ <textarea name="markdown" rows="3"
+ placeholder="{{ trans('entities.comment_placeholder') }}"></textarea>
+ </div>
+ <div class="form-group text-right">
+ <button type="button" class="button outline"
+ action="hideForm">{{ trans('common.cancel') }}</button>
+ <button type="submit" class="button primary">{{ trans('entities.comment_save') }}</button>
+ </div>
+ <div class="form-group loading" style="display: none;">
+ @include('partials.loading-icon', ['text' => trans('entities.comment_saving')])
+ </div>
+ </form>
+ </div>
+</div>
\ No newline at end of file
--- /dev/null
+<header id="header" header-mobile-toggle class="primary-background">
+ <div class="grid mx-l">
+
+ <div>
+ <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 class="mobile-menu-toggle hide-over-l">@icon('more')</div>
+ </div>
+
+ <div class="header-search hide-under-l">
+ @if (hasAppAccess())
+ <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>
+ @endif
+ </div>
+
+ <div class="text-right">
+ <div class="header-links">
+ <div class="links text-center">
+ @if (hasAppAccess())
+ <a class="hide-over-l" href="{{ baseUrl('/search') }}">@icon('search'){{ trans('common.search') }}</a>
+ @if(userCanOnAny('view', \BookStack\Entities\Bookshelf::class) || userCan('bookshelf-view-all') || userCan('bookshelf-view-own'))
+ <a href="{{ baseUrl('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
+ @endif
+ <a href="{{ baseUrl('/books') }}">@icon('books'){{ 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
+ @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())
+ <?php $currentUser = user(); ?>
+ <div class="dropdown-container" dropdown>
+ <span class="user-name hide-under-l" dropdown-toggle>
+ <img class="avatar" src="{{$currentUser->getAvatar(30)}}" alt="{{ $currentUser->name }}">
+ <span class="name">{{ $currentUser->getShortName(9) }}</span> @icon('caret-down')
+ </span>
+ <ul>
+ <li>
+ <a href="{{ baseUrl("/user/{$currentUser->id}") }}">@icon('user'){{ trans('common.view_profile') }}</a>
+ </li>
+ <li>
+ <a href="{{ baseUrl("/settings/users/{$currentUser->id}") }}">@icon('edit'){{ trans('common.edit_profile') }}</a>
+ </li>
+ <li>
+ <a href="{{ baseUrl('/logout') }}">@icon('logout'){{ trans('auth.logout') }}</a>
+ </li>
+ </ul>
+ </div>
+ @endif
+ </div>
+ </div>
+
+ </div>
+</header>
\ No newline at end of file
-@extends('sidebar-layout')
+@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-6 faded">
- <div class="action-buttons text-left">
- <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button">@icon('expand-text'){{ trans('common.toggle_details') }}</a>
- @include('books/view-toggle', ['booksViewType' => $booksViewType])
- </div>
- </div>
-@stop
+@section('body')
+ <div class="container mt-m">
+ <div class="grid right-focus gap-xl">
+ <div>
-@section('sidebar')
- @include('common/home-sidebar')
-@stop
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
+ @include('partials.view-toggle', ['view' => $view, 'type' => 'book'])
+ @include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
+ </div>
+ </div>
-@section('body')
- @include('books/list', ['books' => $books, 'bookViewType' => $booksViewType])
+ @include('common.home-sidebar')
+ </div>
+ <div>
+ @include('books.list', ['books' => $books, 'view' => $view])
+ </div>
+ </div>
+ </div>
@stop
\ No newline at end of file
-@extends('sidebar-layout')
+@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-6 faded">
- <div class="action-buttons text-left">
- <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button">@icon('expand-text'){{ trans('common.toggle_details') }}</a>
- </div>
- </div>
-@stop
+@section('body')
+ <div class="container mt-l">
+ <div class="grid right-focus gap-xl">
+ <div>
-@section('sidebar')
- @include('common/home-sidebar')
-@stop
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
+ @include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
+ </div>
+ </div>
-@section('body')
- <div class="page-content" page-display="{{ $customHomepage->id }}">
- @include('pages/page-display', ['page' => $customHomepage])
+ @include('common.home-sidebar')
+ </div>
+ <div>
+ <div class="content-wrap card">
+ <div class="page-content" page-display="{{ $customHomepage->id }}">
+ @include('pages.page-display', ['page' => $customHomepage])
+ </div>
+ </div>
+ </div>
+ </div>
</div>
-@stop
+@stop
\ No newline at end of file
-@extends('sidebar-layout')
+@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-6 faded">
- <div class="action-buttons text-left">
- <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button">@icon('expand-text'){{ trans('common.toggle_details') }}</a>
- @include('shelves/view-toggle', ['shelvesViewType' => $shelvesViewType])
- </div>
- </div>
-@stop
+@section('body')
+ <div class="container mt-m">
+ <div class="grid right-focus gap-xl">
+ <div>
-@section('sidebar')
- @include('common/home-sidebar')
-@stop
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
+ @include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
+ @include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
+ </div>
+ </div>
-@section('body')
- @include('shelves/list', ['shelves' => $shelves, 'shelvesViewType' => $shelvesViewType])
+ @include('common.home-sidebar')
+ </div>
+ <div>
+ @include('shelves.list', ['shelves' => $shelves, 'view' => $view])
+ </div>
+ </div>
+ </div>
@stop
\ No newline at end of file
@if(count($draftPages) > 0)
- <div id="recent-drafts" class="card">
- <h3>@icon('edit') {{ trans('entities.my_recent_drafts') }}</h3>
- @include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
+ <div id="recent-drafts" class="mb-xl">
+ <h5>{{ trans('entities.my_recent_drafts') }}</h5>
+ @include('partials.entity-list', ['entities' => $draftPages, 'style' => 'compact'])
</div>
@endif
-<div class="card">
- <h3>@icon($signedIn ? 'view' : 'star-circle') {{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3>
- @include('partials/entity-list', [
+<div class="mb-xl">
+ <h5>{{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h5>
+ @include('partials.entity-list', [
'entities' => $recents,
'style' => 'compact',
'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty')
])
</div>
-<div class="card">
- <h3>@icon('file') <a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3>
+<div class="mb-xl">
+ <h5><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h5>
<div id="recently-updated-pages">
- @include('partials/entity-list', [
+ @include('partials.entity-list', [
'entities' => $recentlyUpdatedPages,
'style' => 'compact',
'emptyText' => trans('entities.no_pages_recently_updated')
</div>
</div>
-<div id="recent-activity" class="card">
- <h3>@icon('time') {{ trans('entities.recent_activity') }}</h3>
- @include('partials/activity-list', ['activity' => $activity])
+<div id="recent-activity" class="mb-xl">
+ <h5>{{ trans('entities.recent_activity') }}</h5>
+ @include('partials.activity-list', ['activity' => $activity])
</div>
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-6 faded">
- <div class="action-buttons text-left">
- <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button">@icon('expand-text'){{ trans('common.toggle_details') }}</a>
+@section('body')
+
+ <div class="container px-xl py-s">
+ <div class="icon-list inline block">
+ @include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
</div>
</div>
-@stop
-
-@section('body')
<div class="container" id="home-default">
- <div class="row">
-
- <div class="col-sm-4">
+ <div class="grid third gap-xxl no-row-gap" >
+ <div>
@if(count($draftPages) > 0)
- <div id="recent-drafts" class="card">
- <h3>@icon('edit') {{ trans('entities.my_recent_drafts') }}</h3>
- @include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
+ <div id="recent-drafts" class="card mb-xl">
+ <h3>{{ trans('entities.my_recent_drafts') }}</h3>
+ <div class="px-m">
+ @include('partials.entity-list', ['entities' => $draftPages, 'style' => 'compact'])
+ </div>
</div>
@endif
- <div class="card">
- <h3>@icon($signedIn ? 'view' : 'star-circle') {{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3>
- @include('partials/entity-list', [
+ <div id="{{ $signedIn ? 'recently-viewed' : 'recent-books' }}" class="card mb-xl">
+ <h3>{{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3>
+ <div class="px-m">
+ @include('partials.entity-list', [
'entities' => $recents,
'style' => 'compact',
'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty')
])
+ </div>
</div>
</div>
- <div class="col-sm-4">
- <div class="card">
- <h3>@icon('file') <a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3>
- <div id="recently-updated-pages">
- @include('partials/entity-list', [
+ <div>
+ <div id="recent-pages" class="card mb-xl">
+ <h3><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3>
+ <div id="recently-updated-pages" class="px-m">
+ @include('partials.entity-list', [
'entities' => $recentlyUpdatedPages,
'style' => 'compact',
'emptyText' => trans('entities.no_pages_recently_updated')
</div>
</div>
- <div class="col-sm-4" id="recent-activity">
- <div class="card">
- <h3>@icon('time') {{ trans('entities.recent_activity') }}</h3>
- @include('partials/activity-list', ['activity' => $activity])
+ <div>
+ <div id="recent-activity">
+ <div class="card mb-xl">
+ <h3>{{ trans('entities.recent_activity') }}</h3>
+ @include('partials.activity-list', ['activity' => $activity])
+ </div>
</div>
</div>
</div>
+
@stop
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('components.code_editor') }}</div>
- <button class="overlay-close neg corner-button button" @click="hide()">x</button>
+ <button class="popup-header-close" @click="hide()">x</button>
</div>
- <div class="padded popup-content">
+ <div class="p-l popup-content">
<div class="form-group">
<label for="code-editor-language">{{ trans('components.code_language') }}</label>
<div class="lang-options">
</div>
<div class="form-group">
- <button type="button" class="button pos" @click="save()">{{ trans('components.code_save') }}</button>
+ <button type="button" class="button primary" @click="save()">{{ trans('components.code_save') }}</button>
</div>
</div>
--- /dev/null
+{{--
+$name
+$value
+$checked
+$label
+--}}
+<label class="toggle-switch @if($errors->has($name)) text-neg @endif">
+ <input type="checkbox" name="{{$name}}" value="{{ $value }}" @if($checked) checked="checked" @endif>
+ <span class="custom-checkbox text-primary">@icon('check')</span>
+ <span class="label">{{$label}}</span>
+</label>
\ No newline at end of file
<div id="entity-selector-wrap">
<div overlay entity-selector-popup>
- <div class="popup-body small flex-child">
+ <div class="popup-body small">
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('entities.entity_select') }}</div>
- <button type="button" class="corner-button neg button overlay-close">x</button>
+ <button type="button" class="popup-header-close">x</button>
</div>
@include('components.entity-selector', ['name' => 'entity-selector'])
<div class="popup-footer">
- <button type="button" disabled="true" class="button entity-link-selector-confirm pos corner-button">{{ trans('common.select') }}</button>
+ <button type="button" disabled="true" class="button entity-link-selector-confirm primary corner-button">{{ trans('common.select') }}</button>
</div>
</div>
</div>
-<div class="form-group">
- <div entity-selector class="entity-selector {{$selectorSize or ''}}" entity-types="{{ $entityTypes or 'book,chapter,page' }}" entity-permission="{{ $entityPermission or 'view' }}">
+<div class="form-group entity-selector-container">
+ <div entity-selector class="entity-selector {{$selectorSize ?? ''}}" entity-types="{{ $entityTypes ?? 'book,chapter,page' }}" entity-permission="{{ $entityPermission ?? 'view' }}">
<input type="hidden" entity-selector-input name="{{$name}}" value="">
<input type="text" placeholder="{{ trans('common.search') }}" entity-selector-search>
<div class="text-center loading" entity-selector-loading>@include('partials.loading-icon')</div>
<div entity-selector-results></div>
+ @if($showAdd ?? false)
+ <div class="entity-selector-add">
+ <button entity-selector-add-button type="button"
+ class="button outline">@icon('add'){{ trans('common.add') }}</button>
+ </div>
+ @endif
</div>
</div>
\ No newline at end of file
--- /dev/null
+{{--
+$target - CSS selector of items to expand
+$key - Unique key for checking existing stored state.
+--}}
+<?php $isOpen = setting()->getForCurrentUser('section_expansion#'. $key); ?>
+<a expand-toggle="{{ $target }}"
+ expand-toggle-update-endpoint="{{ baseUrl('/settings/users/'. $currentUser->id .'/update-expansion-preference/' . $key) }}"
+ expand-toggle-is-open="{{ $isOpen ? 'yes' : 'no' }}"
+ class="text-muted icon-list-item text-primary">
+ <span>@icon('expand-text')</span>
+ <span>{{ trans('common.toggle_details') }}</span>
+</a>
+@if($isOpen)
+ @push('head')
+ <style>
+ {{ $target }} {display: block;}
+ </style>
+ @endpush
+@endif
\ No newline at end of file
-<div id="image-manager" image-type="{{ $imageType }}" uploaded-to="{{ $uploaded_to or 0 }}">
+<div id="image-manager" image-type="{{ $imageType }}" uploaded-to="{{ $uploaded_to ?? 0 }}">
<div overlay v-cloak @click="hide">
<div class="popup-body" @click.stop="">
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('components.image_select') }}</div>
- <button class="overlay-close neg corner-button button" @click="hide()">x</button>
+ <button class="popup-header-close" @click="hide()">x</button>
</div>
<div class="flex-fill image-manager-body">
<div class="image-manager-content">
- <div v-if="imageType === 'gallery'" class="container">
- <div class="image-manager-header row faded-small nav-tabs">
- <div class="col-xs-4 tab-item" title="{{ trans('components.image_all_title') }}" :class="{selected: (view=='all')}" @click="setView('all')">@icon('images') {{ trans('components.image_all') }}</div>
- <div class="col-xs-4 tab-item" title="{{ trans('components.image_book_title') }}" :class="{selected: (view=='book')}" @click="setView('book')">@icon('book', ['class' => 'text-book svg-icon']) {{ trans('entities.book') }}</div>
- <div class="col-xs-4 tab-item" title="{{ trans('components.image_page_title') }}" :class="{selected: (view=='page')}" @click="setView('page')">@icon('page', ['class' => 'text-page svg-icon']) {{ trans('entities.page') }}</div>
- </div>
+ <div v-if="imageType === 'gallery'" class="image-manager-header primary-background-light nav-tabs grid third">
+ <div class="tab-item" title="{{ trans('components.image_all_title') }}" :class="{selected: (view=='all')}" @click="setView('all')">@icon('images') {{ trans('components.image_all') }}</div>
+ <div class="tab-item" title="{{ trans('components.image_book_title') }}" :class="{selected: (view=='book')}" @click="setView('book')">@icon('book', ['class' => 'text-book svg-icon']) {{ trans('entities.book') }}</div>
+ <div class="tab-item" title="{{ trans('components.image_page_title') }}" :class="{selected: (view=='page')}" @click="setView('page')">@icon('page', ['class' => 'text-page svg-icon']) {{ trans('entities.page') }}</div>
</div>
<div v-show="view === 'all'" >
<form @submit.prevent="searchImages" class="contained-search-box">
-<div class="image-picker" image-picker="{{$name}}" data-default-image="{{ $defaultImage }}" data-resize-height="{{ $resizeHeight }}" data-resize-width="{{ $resizeWidth }}" data-current-id="{{ $currentId or '' }}" data-resize-crop="{{ $resizeCrop or '' }}">
+<div class="image-picker" image-picker="{{$name}}" data-default-image="{{ $defaultImage }}" data-resize-height="{{ $resizeHeight }}" data-resize-width="{{ $resizeWidth }}" data-current-id="{{ $currentId ?? '' }}" data-resize-crop="{{ $resizeCrop ?? '' }}">
- <div>
- <img @if($currentImage && $currentImage !== 'none') src="{{$currentImage}}" @else src="{{$defaultImage}}" @endif class="{{$imageClass}} @if($currentImage=== 'none') none @endif" alt="{{ trans('components.image_preview') }}">
- </div>
-
- <button class="button" type="button" data-action="show-image-manager">{{ trans('components.image_select_image') }}</button>
- <br>
- <button class="text-button" data-action="reset-image" type="button">{{ trans('common.reset') }}</button>
+ <div class="grid half">
+ <div class="text-center">
+ <img @if($currentImage && $currentImage !== 'none') src="{{$currentImage}}" @else src="{{$defaultImage}}" @endif class="{{$imageClass}} @if($currentImage=== 'none') none @endif" alt="{{ trans('components.image_preview') }}">
+ </div>
+ <div class="text-center">
+ <button class="button outline small" type="button" data-action="show-image-manager">{{ trans('components.image_select_image') }}</button>
+ <br>
+ <button class="text-button text-muted" data-action="reset-image" type="button">{{ trans('common.reset') }}</button>
- @if ($showRemove)
- <span class="sep">|</span>
- <button class="text-button neg" data-action="remove-image" type="button">{{ trans('common.remove') }}</button>
- @endif
+ @if ($showRemove)
+ <span class="sep">|</span>
+ <button class="text-button text-muted" data-action="remove-image" type="button">{{ trans('common.remove') }}</button>
+ @endif
+ </div>
+ </div>
<input type="hidden" name="{{$name}}" id="{{$name}}" value="{{ isset($currentId) && ($currentId !== 0 && $currentId !== false) ? $currentId : $currentImage}}">
</div>
\ No newline at end of file
<div id="tag-manager" entity-id="{{ isset($entity) ? $entity->id : 0 }}" entity-type="{{ $entity ? $entity->getType() : $entityType }}">
<div class="tags">
- <p class="muted small">{!! nl2br(e(trans('entities.tags_explain'))) !!}</p>
+ <p class="text-muted small">{!! nl2br(e(trans('entities.tags_explain'))) !!}</p>
<draggable :options="{handle: '.handle'}" :list="tags" element="div">
-<div toggle-switch="{{$name}}" class="toggle-switch @if($value) active @endif">
+<label toggle-switch="{{$name}}" class="toggle-switch">
<input type="hidden" name="{{$name}}" value="{{$value?'true':'false'}}"/>
- <div class="switch-handle"></div>
-</div>
\ No newline at end of file
+ <input type="checkbox" @if($value) checked="checked" @endif>
+ <span class="custom-checkbox text-primary">@icon('check')</span>
+ <span class="label">{{ $label }}</span>
+</label>
\ No newline at end of file
@extends('simple-layout')
@section('content')
-<div class="container">
+<div class="container mt-l">
- <p> </p>
-
- <div class="card">
- <h3>@icon('danger') {{ $message or trans('errors.404_page_not_found') }}</h3>
- <div class="body">
- <h5>{{ trans('errors.sorry_page_not_found') }}</h5>
- <p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p>
+ <div class="card mb-xl px-l pb-xl pt-l">
+ <div class="grid half v-center">
+ <div>
+ <h1 class="list-heading">{{ $message ?? trans('errors.404_page_not_found') }}</h1>
+ <h5>{{ trans('errors.sorry_page_not_found') }}</h5>
+ </div>
+ <div class="text-right">
+ <a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a>
+ </div>
</div>
+
</div>
@if (setting('app-public') || !user()->isDefault())
- <div class="row">
- <div class="col-md-4">
- <div class="card">
- <h3 class="text-muted">@icon('page') {{ trans('entities.pages_popular') }}</h3>
- @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Entities\Page::class]), 'style' => 'compact'])
+ <div class="grid third gap-xxl">
+ <div>
+ <div class="card mb-xl">
+ <h3>{{ trans('entities.pages_popular') }}</h3>
+ <div class="px-m">
+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, 'page'), 'style' => 'compact'])
+ </div>
</div>
</div>
- <div class="col-md-4">
- <div class="card">
- <h3 class="text-muted">@icon('book') {{ trans('entities.books_popular') }}</h3>
- @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Entities\Book::class]), 'style' => 'compact'])
+ <div>
+ <div class="card mb-xl">
+ <h3>{{ trans('entities.books_popular') }}</h3>
+ <div class="px-m">
+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, 'book'), 'style' => 'compact'])
+ </div>
</div>
</div>
- <div class="col-md-4">
- <div class="card">
- <h3 class="text-muted">@icon('chapter') {{ trans('entities.chapters_popular') }}</h3>
- @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Entities\Chapter::class]), 'style' => 'compact'])
+ <div>
+ <div class="card mb-xl">
+ <h3>{{ trans('entities.chapters_popular') }}</h3>
+ <div class="px-m">
+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, 'chapter'), 'style' => 'compact'])
+ </div>
</div>
</div>
</div>
<div class="card">
<h3 class="text-muted">{{ trans('errors.error_occurred') }}</h3>
<div class="body">
- <h5>{{ $message or 'An unknown error occurred' }}</h5>
+ <h5>{{ $message ?? 'An unknown error occurred' }}</h5>
<p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p>
</div>
</div>
-@extends('public')
+@extends('simple-layout')
@section('content')
- <div class="container small">
- <div class="card">
- <div class="body">
- <h4 class="text-muted">@icon('danger') {{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h4>
- <p>{{ trans('errors.back_soon') }}</p>
- </div>
+ <div class="container small mt-xl">
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h1>
+ <p>{{ trans('errors.back_soon') }}</p>
</div>
</div>
-
-<label>
- <input value="true" id="{{$name}}" type="checkbox" name="{{$name}}"
- @if($errors->has($name)) class="neg" @endif
- @if(old($name) || (!old() && isset($model) && $model->$name)) checked="checked" @endif
- >
- {{ $label }}
-</label>
+{{--
+$name
+$label
+$errors?
+$model?
+--}}
+@include('components.custom-checkbox', [
+ 'name' => $name,
+ 'label' => $label,
+ 'value' => 'true',
+ 'checked' => old($name) || (!old() && isset($model) && $model->$name)
+])
@if($errors->has($name))
<div class="text-neg text-small">{{ $errors->first($name) }}</div>
+++ /dev/null
-<form action="{{$url}}" method="POST" class="inline">
- {{ csrf_field() }}
- <input type="hidden" name="_method" value="DELETE">
- <button type="submit" class="button neg">{{ isset($text) ? $text : trans('common.delete') }}</button>
-</form>
\ No newline at end of file
--- /dev/null
+<form action="{{ $model->getUrl('/permissions') }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
+
+ <p class="mb-none">{{ trans('entities.permissions_intro') }}</p>
+
+ <div class="form-group">
+ @include('form.checkbox', [
+ 'name' => 'restricted',
+ 'label' => trans('entities.permissions_enable'),
+ ])
+ </div>
+
+ <table permissions-table class="table permissions-table toggle-switch-list">
+ <tr>
+ <th>{{ trans('common.role') }}</th>
+ <th @if($model->isA('page')) colspan="3" @else colspan="4" @endif>
+ {{ trans('common.actions') }}
+ <a href="#" permissions-table-toggle-all class="text-small ml-m text-primary">{{ trans('common.toggle_all') }}</a>
+ </th>
+ </tr>
+ @foreach($roles as $role)
+ <tr>
+ <td width="33%" class="pt-m">
+ {{ $role->display_name }}
+ <a href="#" permissions-table-toggle-all-in-row class="text-small float right ml-m text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view'])</td>
+ @if(!$model->isA('page'))
+ <td>@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create'])</td>
+ @endif
+ <td>@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update'])</td>
+ <td>@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete'])</td>
+ </tr>
+ @endforeach
+ </table>
+
+ <div class="text-right">
+ <a href="{{ $model->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('entities.permissions_save') }}</button>
+ </div>
+</form>
\ No newline at end of file
<input type="password" id="{{ $name }}" name="{{ $name }}"
- @if($errors->has($name)) class="neg" @endif
+ @if($errors->has($name)) class="text-neg" @endif
@if(isset($placeholder)) placeholder="{{$placeholder}}" @endif
@if(isset($tabindex)) tabindex="{{$tabindex}}" @endif
@if(old($name)) value="{{ old($name)}}" @endif>
-
-<label>
- <input value="true" id="{{$name}}[{{$role->id}}][{{$action}}]" type="checkbox" name="{{$name}}[{{$role->id}}][{{$action}}]"
- @if(isset($model) && $model->hasRestriction($role->id, $action)) checked="checked" @endif>
- {{ $label }}
-</label>
\ No newline at end of file
+{{--
+$name
+$label
+$role
+$action
+$model?
+--}}
+@include('components.custom-checkbox', [
+ 'name' => $name . '[' . $role->id . '][' . $action . ']',
+ 'label' => $label,
+ 'value' => 'true',
+ 'checked' => isset($model) && $model->hasRestriction($role->id, $action)
+])
\ No newline at end of file
+++ /dev/null
-<form action="{{ $model->getUrl('/permissions') }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="PUT">
-
- <p>{{ trans('entities.permissions_intro') }}</p>
-
- <div class="form-group">
- @include('form/checkbox', ['name' => 'restricted', 'label' => trans('entities.permissions_enable')])
- </div>
-
-
- <table class="table">
- <tr>
- <th>{{ trans('common.role') }}</th>
- <th @if($model->isA('page')) colspan="3" @else colspan="4" @endif>{{ trans('common.actions') }}</th>
- </tr>
- @foreach($roles as $role)
- <tr>
- <td>{{ $role->display_name }}</td>
- <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view'])</td>
- @if(!$model->isA('page'))
- <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create'])</td>
- @endif
- <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update'])</td>
- <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete'])</td>
- </tr>
- @endforeach
- </table>
-
- <div class="text-right">
- <a href="{{ $model->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.permissions_save') }}</button>
- </div>
-</form>
\ No newline at end of file
-@foreach($roles as $role)
- <label>
- <input value="{{ $role->id }}" id="{{$name}}-{{$role->name}}" type="checkbox" name="{{$name}}[{{$role->name}}]"
- @if($errors->has($name)) class="neg" @endif
- @if(old($name . '.' . $role->name) || (!old('name') && isset($model) && $model->hasRole($role->name))) checked="checked" @endif
- >
- {{ $role->display_name }}
- </label>
-@endforeach
+<div class="toggle-switch-list dual-column-content">
+ @foreach($roles as $role)
+ <div>
+ @include('components.custom-checkbox', [
+ 'name' => $name . '[' . str_replace('.', 'DOT', $role->name) . ']',
+ 'label' => $role->display_name,
+ 'value' => $role->id,
+ 'checked' => old($name . '.' . str_replace('.', 'DOT', $role->name)) || (!old('name') && isset($model) && $model->hasRole($role->name))
+ ])
+ </div>
+ @endforeach
+</div>
@if($errors->has($name))
<div class="text-neg text-small">{{ $errors->first($name) }}</div>
<select id="{{ $name }}" name="{{ $name }}">
@foreach($options as $option)
<option value="{{$option->id}}"
- @if($errors->has($name)) class="neg" @endif
+ @if($errors->has($name)) class="text-neg" @endif
@if(isset($model) || old($name)) @if(old($name) && old($name) === $option->id) selected @elseif(isset($model) && $model->role->id === $option->id) selected @endif @endif
>
{{ $option->display_name }}
<input type="text" id="{{ $name }}" name="{{ $name }}"
- @if($errors->has($name)) class="neg" @endif
+ @if($errors->has($name)) class="text-neg" @endif
@if(isset($placeholder)) placeholder="{{$placeholder}}" @endif
@if(isset($tabindex)) tabindex="{{$tabindex}}" @endif
@if(isset($model) || old($name)) value="{{ old($name) ? old($name) : $model->$name}}" @endif>
<textarea id="{{ $name }}" name="{{ $name }}" rows="5"
- @if($errors->has($name)) class="neg" @endif>@if(isset($model) || old($name)){{ old($name) ? old($name) : $model->$name}}@endif</textarea>
+ @if($errors->has($name)) class="text-neg" @endif>@if(isset($model) || old($name)){{ old($name) ? old($name) : $model->$name}}@endif</textarea>
@if($errors->has($name))
<div class="text-neg text-small">{{ $errors->first($name) }}</div>
@endif
\ No newline at end of file
+++ /dev/null
-<div class="breadcrumbs">
- @if (userCan('view', $page->book))
- <a href="{{ $page->book->getUrl() }}" class="text-book text-button">@icon('book'){{ $page->book->getShortName() }}</a>
- <span class="sep">»</span>
- @endif
- @if($page->hasChapter() && userCan('view', $page->chapter))
- <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button">
- @icon('chapter')
- {{ $page->chapter->getShortName() }}
- </a>
- <span class="sep">»</span>
- @endif
- <a href="{{ $page->getUrl() }}" class="text-page text-button">@icon('page'){{ $page->getShortName() }}</a>
-</div>
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('pages._breadcrumbs', ['page' => $page])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('copy') {{ trans('entities.pages_copy') }}</h3>
- <div class="body">
- <form action="{{ $page->getUrl('/copy') }}" method="POST">
- {!! csrf_field() !!}
-
- <div class="form-group title-input">
- <label for="name">{{ trans('common.name') }}</label>
- @include('form/text', ['name' => 'name'])
- </div>
- <div class="form-group" collapsible>
- <div class="collapse-title text-primary" collapsible-trigger>
- <label for="entity_selection">{{ trans('entities.pages_copy_desination') }}</label>
- </div>
- <div class="collapse-content" collapsible-content>
- @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter', 'entityPermission' => 'page-create'])
- </div>
- </div>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/copy') => [
+ 'text' => trans('entities.pages_copy'),
+ 'icon' => 'copy',
+ ]
+ ]])
+ </div>
+ <div class="card content-wrap auto-height">
- <div class="form-group text-right">
- <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.pages_copy') }}</button>
+ <h1 class="list-heading">{{ trans('entities.pages_copy') }}</h1>
+
+ <form action="{{ $page->getUrl('/copy') }}" method="POST">
+ {!! csrf_field() !!}
+
+ <div class="form-group title-input">
+ <label for="name">{{ trans('common.name') }}</label>
+ @include('form.text', ['name' => 'name'])
+ </div>
+
+ <div class="form-group" collapsible>
+ <div class="collapse-title text-primary" collapsible-trigger>
+ <label for="entity_selection">{{ trans('entities.pages_copy_desination') }}</label>
</div>
- </form>
- </div>
+ <div class="collapse-content" collapsible-content>
+ @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter', 'entityPermission' => 'page-create'])
+ </div>
+ </div>
+
+ <div class="form-group text-right">
+ <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('entities.pages_copy') }}</button>
+ </div>
+ </form>
+
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('pages._breadcrumbs', ['page' => $page])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}</h3>
- <div class="body">
- <p class="text-neg">{{ $page->draft ? trans('entities.pages_delete_draft_confirm'): trans('entities.pages_delete_confirm') }}</p>
- <form action="{{ $page->getUrl() }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
- <div class="form-group">
- <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
- </div>
- </form>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/delete') => [
+ 'text' => trans('entities.pages_delete'),
+ 'icon' => 'delete',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}</h1>
+
+
+ <div class="grid half v-center">
+ <div>
+ <p class="text-neg">
+ <strong>
+ {{ $page->draft ? trans('entities.pages_delete_draft_confirm'): trans('entities.pages_delete_confirm') }}
+ </strong>
+ </p>
+ </div>
+ <div>
+ <form action="{{ $page->getUrl() }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
+ <div class="form-group text-right">
+ <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
+ </div>
+ </form>
+ </div>
</div>
</div>
</div>
@extends('simple-layout')
@section('body')
- <div class="container small">
- <p> </p>
- <div class="card">
- <h3>{{ $title }}</h3>
- @include('partials/entity-list', ['entities' => $pages, 'style' => 'detailed'])
- <div class="body text-center">
+ <div class="container small pt-xl">
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ $title }}</h1>
+
+ <div class="book-contents">
+ @include('partials.entity-list', ['entities' => $pages, 'style' => 'detailed'])
+ </div>
+
+ <div class="text-center">
{!! $pages->links() !!}
</div>
</div>
-
</div>
@stop
\ No newline at end of file
@if(!isset($isDraft))
<input type="hidden" name="_method" value="PUT">
@endif
- @include('pages/form', ['model' => $page])
- @include('pages/form-toolbox')
+ @include('pages.form', ['model' => $page])
+ @include('pages.form-toolbox')
</form>
</div>
@include('partials.custom-head')
</head>
<body>
-<div class="container" id="page-show">
- <div class="row">
- <div class="col-md-8 col-md-offset-2">
- <div class="page-content">
- @include('pages.page-display')
+<div id="page-show">
+ <div class="page-content">
- <hr>
+ @include('pages.page-display')
- <div class="text-muted text-small">
- @include('partials.entity-export-meta', ['entity' => $page])
- </div>
+ <hr>
- </div>
+ <div class="text-muted text-small">
+ @include('partials.entity-export-meta', ['entity' => $page])
</div>
+
</div>
</div>
+
</body>
</html>
<div toolbox-tab-content="tags">
<h4>{{ trans('entities.page_tags') }}</h4>
- <div class="padded">
+ <div class="px-l">
@include('components.tag-manager', ['entity' => $page, 'entityType' => 'page'])
</div>
</div>
@if(userCan('attachment-create-all'))
- <div toolbox-tab-content="files" id="attachment-manager" page-id="{{ $page->id or 0 }}">
+ <div toolbox-tab-content="files" id="attachment-manager" page-id="{{ $page->id ?? 0 }}">
<h4>{{ trans('entities.attachments') }}</h4>
- <div class="padded files">
+ <div class="px-l files">
<div id="file-list" v-show="!fileToEdit">
- <p class="muted small">{{ trans('entities.attachments_explain') }} <span class="secondary">{{ trans('entities.attachments_explain_instant_save') }}</span></p>
+ <p class="text-muted small">{{ trans('entities.attachments_explain') }} <span class="text-warn">{{ trans('entities.attachments_explain_instant_save') }}</span></p>
<div class="tab-container">
<div class="nav-tabs">
<draggable style="width: 100%;" :options="{handle: '.handle'}" @change="fileSortUpdate" :list="files" element="div">
<div v-for="(file, index) in files" :key="file.id" class="card drag-card">
<div class="handle">@icon('grip')</div>
- <div class="padded">
+ <div class="py-s">
<a :href="getFileUrl(file)" target="_blank" v-text="file.name"></a>
<div v-if="file.deleting">
- <span class="neg small">{{ trans('entities.attachments_delete_confirm') }}</span>
+ <span class="text-neg small">{{ trans('entities.attachments_delete_confirm') }}</span>
<br>
<span class="text-primary small" @click="file.deleting = false;">{{ trans('common.cancel') }}</span>
</div>
<div @click="deleteFile(file)" class="drag-card-action text-center text-neg">@icon('close')</div>
</div>
</draggable>
- <p class="small muted" v-if="files.length === 0">
+ <p class="small text-muted" v-if="files.length === 0">
{{ trans('entities.attachments_no_files') }}
</p>
</div>
<dropzone placeholder="{{ trans('entities.attachments_dropzone') }}" :upload-url="getUploadUrl()" :uploaded-to="pageId" @success="uploadSuccess"></dropzone>
</div>
<div v-show="tab === 'link'" @keypress.enter.prevent="attachNewLink(file)">
- <p class="muted small">{{ trans('entities.attachments_explain_link') }}</p>
+ <p class="text-muted small">{{ trans('entities.attachments_explain_link') }}</p>
<div class="form-group">
<label for="attachment-via-link">{{ trans('entities.attachments_link_name') }}</label>
<input type="text" placeholder="{{ trans('entities.attachments_link_name') }}" v-model="file.name">
- <p class="small neg" v-for="error in errors.link.name" v-text="error"></p>
+ <p class="small text-neg" v-for="error in errors.link.name" v-text="error"></p>
</div>
<div class="form-group">
<label for="attachment-via-link">{{ trans('entities.attachments_link_url') }}</label>
<input type="text" placeholder="{{ trans('entities.attachments_link_url_hint') }}" v-model="file.link">
- <p class="small neg" v-for="error in errors.link.link" v-text="error"></p>
+ <p class="small text-neg" v-for="error in errors.link.link" v-text="error"></p>
</div>
- <button @click.prevent="attachNewLink(file)" class="button pos">{{ trans('entities.attach') }}</button>
+ <button @click.prevent="attachNewLink(file)" class="button primary">{{ trans('entities.attach') }}</button>
</div>
</div>
<div class="form-group">
<label for="attachment-name-edit">{{ trans('entities.attachments_edit_file_name') }}</label>
<input type="text" id="attachment-name-edit" placeholder="{{ trans('entities.attachments_edit_file_name') }}" v-model="fileToEdit.name">
- <p class="small neg" v-for="error in errors.edit.name" v-text="error"></p>
+ <p class="small text-neg" v-for="error in errors.edit.name" v-text="error"></p>
</div>
<div class="tab-container">
<div class="form-group">
<label for="attachment-link-edit">{{ trans('entities.attachments_link_url') }}</label>
<input type="text" id="attachment-link-edit" placeholder="{{ trans('entities.attachment_link') }}" v-model="fileToEdit.link">
- <p class="small neg" v-for="error in errors.edit.link" v-text="error"></p>
+ <p class="small text-neg" v-for="error in errors.edit.link" v-text="error"></p>
</div>
</div>
</div>
<button type="button" class="button outline" @click="cancelEdit">{{ trans('common.back') }}</button>
- <button @click.enter.prevent="updateFile(fileToEdit)" class="button pos">{{ trans('common.save') }}</button>
+ <button @click.enter.prevent="updateFile(fileToEdit)" class="button primary">{{ trans('common.save') }}</button>
</div>
</div>
drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}"
drawio-enabled="{{ config('services.drawio') ? 'true' : 'false' }}"
editor-type="{{ setting('app-editor') }}"
- page-id="{{ $model->id or 0 }}"
+ page-id="{{ $model->id ?? 0 }}"
text-direction="{{ config('app.rtl') ? 'rtl' : 'ltr' }}"
- page-new-draft="{{ $model->draft or 0 }}"
- page-update-draft="{{ $model->isDraft or 0 }}">
+ page-new-draft="{{ $model->draft ?? 0 }}"
+ page-update-draft="{{ $model->isDraft ?? 0 }}">
{{ csrf_field() }}
{{--Header Bar--}}
- <div class="faded-small toolbar">
- <div class="container fluid">
- <div class="row">
- <div class="col-sm-4 faded">
- <div class="action-buttons text-left">
- <a href="{{ back()->getTargetUrl() }}" class="text-button text-primary">@icon('back'){{ trans('common.back') }}</a>
- <a onclick="$('body>header').slideToggle();" class="text-button text-primary">@icon('swap-vertical'){{ trans('entities.pages_edit_toggle_header') }}</a>
- </div>
- </div>
- <div class="col-sm-4 faded text-center">
-
- <div v-show="draftsEnabled" dropdown class="dropdown-container draft-display">
- <a dropdown-toggle class="text-primary text-button"><span class="faded-text" v-text="draftText"></span> @icon('more')</a>
- @icon('check-circle', ['class' => 'text-pos draft-notification svg-icon', ':class' => '{visible: draftUpdated}'])
- <ul>
- <li>
- <a @click="saveDraft()" class="text-pos">@icon('save'){{ trans('entities.pages_edit_save_draft') }}</a>
- </li>
- <li v-if="isNewDraft">
- <a href="{{ $model->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('entities.pages_edit_delete_draft') }}</a>
- </li>
- <li v-if="isUpdateDraft">
- <a type="button" @click="discardDraft" class="text-neg">@icon('cancel'){{ trans('entities.pages_edit_discard_draft') }}</a>
- </li>
- </ul>
- </div>
+ <div class="primary-background-light toolbar page-edit-toolbar">
+ <div class="grid third v-center">
+
+ <div class="action-buttons text-left px-m py-xs">
+ <a href="{{ back()->getTargetUrl() }}" class="text-button text-primary">@icon('back')<span class="hide-under-l">{{ trans('common.back') }}</span></a>
+ <a onclick="$('body>header').slideToggle();" class="text-button text-primary">@icon('swap-vertical')<span class="hide-under-l">{{ trans('entities.pages_edit_toggle_header') }}</span></a>
+ </div>
+
+ <div class="text-center px-m py-xs">
+ <div v-show="draftsEnabled" dropdown class="dropdown-container draft-display text">
+ <a dropdown-toggle class="text-primary text-button"><span class="faded-text" v-text="draftText"></span> @icon('more')</a>
+ @icon('check-circle', ['class' => 'text-pos draft-notification svg-icon', ':class' => '{visible: draftUpdated}'])
+ <ul>
+ <li>
+ <a @click="saveDraft()" class="text-pos">@icon('save'){{ trans('entities.pages_edit_save_draft') }}</a>
+ </li>
+ <li v-if="isNewDraft">
+ <a href="{{ $model->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('entities.pages_edit_delete_draft') }}</a>
+ </li>
+ <li v-if="isUpdateDraft">
+ <a type="button" @click="discardDraft" class="text-neg">@icon('cancel'){{ trans('entities.pages_edit_discard_draft') }}</a>
+ </li>
+ </ul>
</div>
- <div class="col-sm-4 faded">
- <div class="action-buttons" v-cloak>
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('edit') <span v-text="changeSummaryShort"></span></a>
- <ul class="wide">
- <li class="padded">
- <p class="text-muted">{{ trans('entities.pages_edit_enter_changelog_desc') }}</p>
- <input name="summary" id="summary-input" type="text" placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" v-model="changeSummary" />
- </li>
- </ul>
- </div>
+ </div>
- <button type="submit" id="save-button" class="text-button text-pos">@icon('save'){{ trans('entities.pages_save') }}</button>
- </div>
+ <div class="action-buttons px-m py-xs" v-cloak>
+ <div dropdown class="dropdown-container">
+ <a dropdown-toggle class="text-primary text-button">@icon('edit') <span v-text="changeSummaryShort"></span></a>
+ <ul class="wide">
+ <li class="px-l py-m">
+ <p class="text-muted pb-s">{{ trans('entities.pages_edit_enter_changelog_desc') }}</p>
+ <input name="summary" id="summary-input" type="text" placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" v-model="changeSummary" />
+ </li>
+ </ul>
</div>
+
+ <button type="submit" id="save-button" class="float-left text-primary text-button text-pos-hover">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
</div>
</div>
</div>
{{--Title input--}}
<div class="title-input page-title clearfix" v-pre>
<div class="input">
- @include('form/text', ['name' => 'name', 'placeholder' => trans('entities.pages_title')])
+ @include('form.text', ['name' => 'name', 'placeholder' => trans('entities.pages_title')])
</div>
</div>
@if(setting('app-editor') === 'wysiwyg')
<div wysiwyg-editor class="flex-fill flex">
<textarea id="html-editor" name="html" rows="5" v-pre
- @if($errors->has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
+ @if($errors->has('html')) class="text-neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
</div>
@if($errors->has('html'))
@if(setting('app-editor') === 'markdown')
<div v-pre id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
- <div class="markdown-editor-wrap">
+ <div class="markdown-editor-wrap active">
<div class="editor-toolbar">
- <span class="float left">{{ trans('entities.pages_md_editor') }}</span>
+ <span class="float left editor-toolbar-label">{{ trans('entities.pages_md_editor') }}</span>
<div class="float right buttons">
@if(config('services.drawio'))
<button class="text-button" type="button" data-action="insertDrawing">@icon('drawing'){{ trans('entities.pages_md_insert_drawing') }}</button>
<div markdown-input class="flex flex-fill">
<textarea id="markdown-editor-input" name="markdown" rows="5"
- @if($errors->has('markdown')) class="neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
+ @if($errors->has('markdown')) class="text-neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
</div>
</div>
<div class="markdown-editor-wrap">
<div class="editor-toolbar">
- <div class="">{{ trans('entities.pages_md_preview') }}</div>
+ <div class="editor-toolbar-label">{{ trans('entities.pages_md_preview') }}</div>
</div>
<div class="markdown-display page-content">
</div>
-@extends('base')
+@extends('simple-layout')
-@section('content')
+@section('body')
<div class="container small">
- <h1>{{ trans('entities.pages_new') }}</h1>
- <form action="{{ $parent->getUrl('/create-guest-page') }}" method="POST">
- {!! csrf_field() !!}
-
- <div class="form-group title-input">
- <label for="name">{{ trans('entities.pages_name') }}</label>
- @include('form/text', ['name' => 'name'])
- </div>
-
- <div class="form-group">
- <a href="{{ $parent->getUrl() }}" class="button muted">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('common.continue') }}</button>
- </div>
-
- </form>
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ ($parent->isA('chapter') ? $parent->book : null),
+ $parent,
+ $parent->getUrl('/create-page') => [
+ 'text' => trans('entities.pages_new'),
+ 'icon' => 'add',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.pages_new') }}</h1>
+ <form action="{{ $parent->getUrl('/create-guest-page') }}" method="POST">
+ {!! csrf_field() !!}
+
+ <div class="form-group title-input">
+ <label for="name">{{ trans('entities.pages_name') }}</label>
+ @include('form.text', ['name' => 'name'])
+ </div>
+
+ <div class="form-group text-right">
+ <a href="{{ $parent->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('common.continue') }}</button>
+ </div>
+
+ </form>
+ </div>
</div>
-
@stop
\ No newline at end of file
-<div class="page {{$page->draft ? 'draft' : ''}} entity-list-item" data-entity-type="page" data-entity-id="{{$page->id}}">
- <h4>
- @if (isset($showPath) && $showPath)
- <a href="{{ $page->book->getUrl() }}" class="text-book">
- @icon('book'){{ $page->book->getShortName() }}
- </a>
- <span class="text-muted"> » </span>
- @if($page->chapter)
- <a href="{{ $page->chapter->getUrl() }}" class="text-chapter">
- @icon('chapter'){{ $page->chapter->getShortName() }}
- </a>
- <span class="text-muted"> » </span>
- @endif
- @endif
- <a href="{{ $page->getUrl() }}" class="text-page entity-list-item-link">@icon('page')<span class="entity-list-item-name break-text">{{ $page->name }}</span></a>
- </h4>
-
+@component('partials.entity-list-item-basic', ['entity' => $page])
<div class="entity-item-snippet">
- @if(isset($page->searchSnippet))
- <p class="text-muted break-text">{!! $page->searchSnippet !!}</p>
- @else
- <p class="text-muted break-text">{{ $page->getExcerpt() }}</p>
- @endif
+ <p class="text-muted break-text">{{ $page->getExcerpt() }}</p>
</div>
-
- @if(isset($style) && $style === 'detailed')
- <div class="row meta text-muted text-small">
- <div class="col-md-6">
- @include('partials.entity-meta', ['entity' => $page])
- </div>
- <div class="col-md-6">
- <a class="text-book" href="{{ $page->book->getUrl() }}">@icon('book'){{ $page->book->getShortName(30) }}</a>
- <br>
- @if($page->chapter)
- <a class="text-chapter" href="{{ $page->chapter->getUrl() }}">@icon('chapter'){{ $page->chapter->getShortName(30) }}</a>
- @else
- @icon('chapter') {{ trans('entities.pages_not_in_chapter') }}
- @endif
- </div>
- </div>
- @endif
-
-
-</div>
\ No newline at end of file
+@endcomponent
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('pages._breadcrumbs', ['page' => $page])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('folder') {{ trans('entities.pages_move') }}</h3>
- <div class="body">
- <form action="{{ $page->getUrl('/move') }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="PUT">
-
- @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter', 'entityPermission' => 'page-create'])
-
- <div class="form-group text-right">
- <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.pages_move') }}</button>
- </div>
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/move') => [
+ 'text' => trans('entities.pages_move'),
+ 'icon' => 'folder',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.pages_move') }}</h1>
+
+ <form action="{{ $page->getUrl('/move') }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
+
+ @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter', 'entityPermission' => 'page-create'])
+
+ <div class="form-group text-right">
+ <a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('entities.pages_move') }}</button>
+ </div>
+ </form>
+
</div>
</div>
--- /dev/null
+@extends('simple-layout')
+
+@section('body')
+
+ <div class="container">
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/permissions') => [
+ 'text' => trans('entities.pages_permissions'),
+ 'icon' => 'lock',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.pages_permissions') }}</h1>
+ @include('form.entity-permissions', ['model' => $page])
+ </div>
+ </div>
+
+@stop
+++ /dev/null
-@extends('simple-layout')
-
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('pages._breadcrumbs', ['page' => $page])
- </div>
-@stop
-
-@section('body')
- <div class="container">
- <p> </p>
- <div class="card">
- <h3>@icon('lock') {{ trans('entities.pages_permissions') }}</h3>
- <div class="body">
- @include('form.restriction-form', ['model' => $page])
- </div>
- </div>
- </div>
-@stop
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('sidebar')
- <div class="card">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
+@section('left')
+ <div id="revision-details" class="entity-details mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
<div class="body text-small text-muted">
@include('partials.entity-meta', ['entity' => $revision])
</div>
@section('body')
- <div class="container">
- <div class="row">
- <div class="col-md-9">
- <div class="page-content page-revision">
- @include('pages.page-display')
- </div>
- </div>
- </div>
+ <div class="mb-m">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->$book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/revisions') => [
+ 'text' => trans('entities.pages_revisions'),
+ 'icon' => 'history',
+ ],
+ $revision->getUrl('/changes') => $diff ? trans('entities.pages_revisions_numbered_changes', ['id' => $revision->id]) : null,
+ $revision->getUrl() => !$diff ? trans('entities.pages_revisions_numbered', ['id' => $revision->id]) : null,
+ ]])
</div>
-@stop
+ <div class="card content-wrap">
+ <div class="page-content page-revision">
+ @include('pages.page-display')
+ </div>
+ </div>
-@section('scripts')
- <script>
- setupPageShow(null);
- </script>
@stop
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('pages._breadcrumbs', ['page' => $page])
- </div>
-@stop
-
@section('body')
<div class="container">
- <p> </p>
- <div class="card">
- <h3>@icon('history') {{ trans('entities.pages_revisions') }}</h3>
- <div class="body">
- @if(count($page->revisions) > 0)
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/revisions') => [
+ 'text' => trans('entities.pages_revisions'),
+ 'icon' => 'history',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.pages_revisions') }}</h1>
+ @if(count($page->revisions) > 0)
- <table class="table">
+ <table class="table">
+ <tr>
+ <th width="3%">{{ trans('entities.pages_revisions_number') }}</th>
+ <th width="23%">{{ trans('entities.pages_name') }}</th>
+ <th colspan="2" width="8%">{{ trans('entities.pages_revisions_created_by') }}</th>
+ <th width="15%">{{ trans('entities.pages_revisions_date') }}</th>
+ <th width="25%">{{ trans('entities.pages_revisions_changelog') }}</th>
+ <th width="20%">{{ trans('common.actions') }}</th>
+ </tr>
+ @foreach($page->revisions as $index => $revision)
<tr>
- <th width="3%">{{ trans('entities.pages_revisions_number') }}</th>
- <th width="23%">{{ trans('entities.pages_name') }}</th>
- <th colspan="2" width="8%">{{ trans('entities.pages_revisions_created_by') }}</th>
- <th width="15%">{{ trans('entities.pages_revisions_date') }}</th>
- <th width="25%">{{ trans('entities.pages_revisions_changelog') }}</th>
- <th width="20%">{{ trans('common.actions') }}</th>
- </tr>
- @foreach($page->revisions as $index => $revision)
- <tr>
- <td>{{ $revision->revision_number == 0 ? '' : $revision->revision_number }}</td>
- <td>{{ $revision->name }}</td>
- <td style="line-height: 0;">
- @if($revision->createdBy)
- <img class="avatar" src="{{ $revision->createdBy->getAvatar(30) }}" alt="{{ $revision->createdBy->name }}">
- @endif
- </td>
- <td> @if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif</td>
- <td><small>{{ $revision->created_at->formatLocalized('%e %B %Y %H:%M:%S') }} <br> ({{ $revision->created_at->diffForHumans() }})</small></td>
- <td>{{ $revision->summary }}</td>
- <td class="actions">
- <a href="{{ $revision->getUrl('changes') }}" target="_blank">{{ trans('entities.pages_revisions_changes') }}</a>
- <span class="text-muted"> | </span>
+ <td>{{ $revision->revision_number == 0 ? '' : $revision->revision_number }}</td>
+ <td>{{ $revision->name }}</td>
+ <td style="line-height: 0;">
+ @if($revision->createdBy)
+ <img class="avatar" src="{{ $revision->createdBy->getAvatar(30) }}" alt="{{ $revision->createdBy->name }}">
+ @endif
+ </td>
+ <td> @if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif</td>
+ <td><small>{{ $revision->created_at->formatLocalized('%e %B %Y %H:%M:%S') }} <br> ({{ $revision->created_at->diffForHumans() }})</small></td>
+ <td>{{ $revision->summary }}</td>
+ <td class="actions">
+ <a href="{{ $revision->getUrl('changes') }}" target="_blank">{{ trans('entities.pages_revisions_changes') }}</a>
+ <span class="text-muted"> | </span>
- @if ($index === 0)
- <a target="_blank" href="{{ $page->getUrl() }}"><i>{{ trans('entities.pages_revisions_current') }}</i></a>
- @else
- <a href="{{ $revision->getUrl() }}" target="_blank">{{ trans('entities.pages_revisions_preview') }}</a>
- <span class="text-muted"> | </span>
- <a href="{{ $revision->getUrl('restore') }}">{{ trans('entities.pages_revisions_restore') }}</a>
- <span class="text-muted"> | </span>
- <div dropdown class="dropdown-container">
- <a dropdown-toggle>{{ trans('common.delete') }}</a>
- <ul>
- <li class="padded"><small class="text-muted">{{trans('entities.revision_delete_confirm')}}</small></li>
- <li>
- <form action="{{ $revision->getUrl('/delete/') }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
- <button type="submit" class="text-button neg">@icon('delete'){{ trans('common.delete') }}</button>
- </form>
- </li>
- </ul>
- </div>
- @endif
- </td>
- </tr>
- @endforeach
- </table>
+ @if ($index === 0)
+ <a target="_blank" href="{{ $page->getUrl() }}"><i>{{ trans('entities.pages_revisions_current') }}</i></a>
+ @else
+ <a href="{{ $revision->getUrl() }}" target="_blank">{{ trans('entities.pages_revisions_preview') }}</a>
+ <span class="text-muted"> | </span>
+ <a href="{{ $revision->getUrl('restore') }}"></a>
+ <div dropdown class="dropdown-container">
+ <a dropdown-toggle>{{ trans('entities.pages_revisions_restore') }}</a>
+ <ul>
+ <li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_restore_confirm')}}</small></li>
+ <li>
+ <form action="{{ $revision->getUrl('/restore') }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
+ <button type="submit" class="text-button text-primary">@icon('history'){{ trans('entities.pages_revisions_restore') }}</button>
+ </form>
+ </li>
+ </ul>
+ </div>
+ <span class="text-muted"> | </span>
+ <div dropdown class="dropdown-container">
+ <a dropdown-toggle>{{ trans('common.delete') }}</a>
+ <ul>
+ <li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_delete_confirm')}}</small></li>
+ <li>
+ <form action="{{ $revision->getUrl('/delete/') }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
+ <button type="submit" class="text-button text-neg">@icon('delete'){{ trans('common.delete') }}</button>
+ </form>
+ </li>
+ </ul>
+ </div>
+ @endif
+ </td>
+ </tr>
+ @endforeach
+ </table>
- @else
- <p>{{ trans('entities.pages_revisions_none') }}</p>
- @endif
- </div>
+ @else
+ <p>{{ trans('entities.pages_revisions_none') }}</p>
+ @endif
</div>
</div>
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-sm-8 col-xs-5 faded">
- @include('pages._breadcrumbs', ['page' => $page])
+@section('body')
+
+ <div class="mb-m">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->hasChapter() ? $page->chapter : null,
+ $page,
+ ]])
</div>
- <div class="col-sm-4 col-xs-7 faded">
- <div class="action-buttons">
- <span dropdown class="dropdown-container">
- <div dropdown-toggle class="text-button text-primary">@icon('export'){{ trans('entities.export') }}</div>
- <ul class="wide">
- <li><a href="{{ $page->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
- <li><a href="{{ $page->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
- <li><a href="{{ $page->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
- </ul>
- </span>
- @if(userCan('page-update', $page))
- <a href="{{ $page->getUrl('/edit') }}" class="text-primary text-button" >@icon('edit'){{ trans('common.edit') }}</a>
- @endif
- @if((userCan('page-view', $page) && userCanOnAny('page-create')) || userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page))
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('more') {{ trans('common.more') }}</a>
- <ul>
- @if(userCanOnAny('page-create'))
- <li><a href="{{ $page->getUrl('/copy') }}" class="text-primary" >@icon('copy'){{ trans('common.copy') }}</a></li>
- @endif
- @if(userCan('page-delete', $page) && userCan('page-update', $page))
- <li><a href="{{ $page->getUrl('/move') }}" class="text-primary" >@icon('folder'){{ trans('common.move') }}</a></li>
- @endif
- @if(userCan('page-update', $page))
- <li><a href="{{ $page->getUrl('/revisions') }}" class="text-primary">@icon('history'){{ trans('entities.revisions') }}</a></li>
- @endif
- @if(userCan('restrictions-manage', $page))
- <li><a href="{{ $page->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li>
- @endif
- @if(userCan('page-delete', $page))
- <li><a href="{{ $page->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li>
- @endif
- </ul>
+
+ <div class="content-wrap card">
+ <div class="page-content flex" page-display="{{ $page->id }}">
+
+ <div class="pointer-container" id="pointer">
+ <div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
+ <span class="icon text-primary">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
+ <span class="input-group">
+ <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
+ <button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
+ </span>
+ @if(userCan('page-update', $page))
+ <a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
+ class="button icon heading-edit-icon" title="{{ trans('entities.pages_edit_content_link')}}">@icon('edit')</a>
+ @endif
</div>
- @endif
+ </div>
+ @include('pages.page-display')
</div>
</div>
+
+ @if ($commentsEnabled)
+ <div class="container small p-none comments-container mb-l">
+ @include('comments.comments', ['page' => $page])
+ <div class="clearfix"></div>
+ </div>
+ @endif
@stop
-@section('sidebar')
+@section('left')
@if($page->tags->count() > 0)
<section>
@endif
@if ($page->attachments->count() > 0)
- <div class="card">
- <h3>@icon('attach') {{ trans('entities.pages_attachments') }}</h3>
+ <div id="page-attachments" class="mb-l">
+ <h5>{{ trans('entities.pages_attachments') }}</h5>
<div class="body">
@foreach($page->attachments as $attachment)
- <div class="attachment">
- <a href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>@icon($attachment->external ? 'export' : 'file'){{ $attachment->name }}</a>
+ <div class="attachment icon-list">
+ <a class="icon-list-item py-xs" href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>
+ <span class="icon">@icon($attachment->external ? 'export' : 'file')</span>
+ <span>{{ $attachment->name }}</span>
+ </a>
</div>
@endforeach
</div>
@endif
@if (isset($pageNav) && count($pageNav))
- <div class="card">
- <h3>@icon('open-book') {{ trans('entities.pages_navigation') }}</h3>
+ <div id="page-navigation" class="mb-xl">
+ <h5>{{ trans('entities.pages_navigation') }}</h5>
<div class="body">
<div class="sidebar-page-nav menu">
@foreach($pageNav as $navItem)
<li class="page-nav-item h{{ $navItem['level'] }}">
<a href="{{ $navItem['link'] }}">{{ $navItem['text'] }}</a>
+ <div class="primary-background sidebar-page-nav-bullet"></div>
</li>
@endforeach
</div>
</div>
@endif
- <div class="card entity-details">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
- <div class="body text-muted text-small blended-links">
+ @include('partials.book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
+@stop
+
+@section('right')
+ <div id="page-details" class="entity-details mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
+ <div class="body text-small blended-links">
@include('partials.entity-meta', ['entity' => $page])
@if($book->restricted)
</div>
</div>
- @include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
+ <div class="actions mb-xl">
+ <h5>Actions</h5>
-@stop
+ <div class="icon-list text-primary">
-@section('body-wrap-classes', 'flex-fill columns')
-
-@section('body')
+ {{--User Actions--}}
+ @if(userCan('page-update', $page))
+ <a href="{{ $page->getUrl('/edit') }}" class="icon-list-item">
+ <span>@icon('edit')</span>
+ <span>{{ trans('common.edit') }}</span>
+ </a>
+ @endif
+ @if(userCanOnAny('page-create'))
+ <a href="{{ $page->getUrl('/copy') }}" class="icon-list-item">
+ <span>@icon('copy')</span>
+ <span>{{ trans('common.copy') }}</span>
+ </a>
+ @endif
+ @if(userCan('page-update', $page))
+ @if(userCan('page-delete', $page))
+ <a href="{{ $page->getUrl('/move') }}" class="icon-list-item">
+ <span>@icon('folder')</span>
+ <span>{{ trans('common.move') }}</span>
+ </a>
+ @endif
+ <a href="{{ $page->getUrl('/revisions') }}" class="icon-list-item">
+ <span>@icon('history')</span>
+ <span>{{ trans('entities.revisions') }}</span>
+ </a>
+ @endif
+ @if(userCan('restrictions-manage', $page))
+ <a href="{{ $page->getUrl('/permissions') }}" class="icon-list-item">
+ <span>@icon('lock')</span>
+ <span>{{ trans('entities.permissions') }}</span>
+ </a>
+ @endif
+ @if(userCan('page-delete', $page))
+ <a href="{{ $page->getUrl('/delete') }}" class="icon-list-item">
+ <span>@icon('delete')</span>
+ <span>{{ trans('common.delete') }}</span>
+ </a>
+ @endif
- <div class="page-content flex" page-display="{{ $page->id }}">
+ <hr class="primary-background"/>
- <div class="pointer-container" id="pointer">
- <div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
- <span class="icon text-primary">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
- <span class="input-group">
- <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
- <button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
- </span>
- @if(userCan('page-update', $page))
- <a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
- class="button icon heading-edit-icon" title="{{ trans('entities.pages_edit_content_link')}}">@icon('edit')</a>
- @endif
+ {{--Export--}}
+ <div dropdown class="dropdown-container block">
+ <div dropdown-toggle class="icon-list-item">
+ <span>@icon('export')</span>
+ <span>{{ trans('entities.export') }}</span>
+ </div>
+ <ul class="wide">
+ <li><a href="{{ $page->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
+ <li><a href="{{ $page->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
+ <li><a href="{{ $page->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
+ </ul>
</div>
</div>
- @include('pages/page-display')
</div>
-
- @if ($commentsEnabled)
- <div class="container small nopad comments-container">
- @include('comments/comments', ['page' => $page])
- </div>
- @endif
@stop
+++ /dev/null
-<div class="dropdown-container" dropdown>
- <span class="user-name" dropdown-toggle>
- <img class="avatar" src="{{$currentUser->getAvatar(30)}}" alt="{{ $currentUser->name }}">
- <span class="name">{{ $currentUser->getShortName(9) }}</span> @icon('caret-down')
- </span>
- <ul>
- <li>
- <a href="{{ baseUrl("/user/{$currentUser->id}") }}" class="text-primary">@icon('user') {{ trans('common.view_profile') }}</a>
- </li>
- <li>
- <a href="{{ baseUrl("/settings/users/{$currentUser->id}") }}" class="text-primary">@icon('edit') {{ trans('common.edit_profile') }}</a>
- </li>
- <li>
- <a href="{{ baseUrl('/logout') }}" class="text-neg">@icon('logout') {{ trans('auth.logout') }}</a>
- </li>
- </ul>
-</div>
\ No newline at end of file
{{--Requires an Activity item with the name $activity passed in--}}
-@if($activity->user)
- <div class="left">
- <img class="avatar" src="{{ $activity->user->getAvatar(30) }}" alt="{{ $activity->user->name }}">
- </div>
-@endif
+<div>
+ @if($activity->user)
+ <img class="avatar" src="{{ $activity->user->getAvatar(30) }}" alt="{{ $activity->user->name }}">
+ @endif
+</div>
-<div class="right" v-pre>
+<div v-pre>
@if($activity->user)
<a href="{{ $activity->user->getProfileUrl() }}">{{ $activity->user->name }}</a>
@else
<div class="activity-list">
@foreach($activity as $activityItem)
<div class="activity-list-item">
- @include('partials/activity-item', ['activity' => $activityItem])
+ @include('partials.activity-item', ['activity' => $activityItem])
</div>
@endforeach
</div>
-<div class="card book-tree" v-pre>
- <h3>@icon('book') {{ trans('entities.books_navigation') }}</h3>
- <div class="body">
- <ul class="sidebar-page-list menu">
+<div id="book-tree" class="book-tree mb-xl" v-pre>
+ <h5>{{ trans('entities.books_navigation') }}</h5>
- @if (userCan('view', $book))
- <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}">@icon('book'){{$book->name}}</a></li>
- @endif
+ <ul class="sidebar-page-list mt-xs menu entity-list">
+ @if (userCan('view', $book))
+ <li class="list-item-book book">
+ @include('partials.entity-list-item-basic', ['entity' => $book, 'classes' => ($current->matches($book)? 'selected' : '')])
+ </li>
+ @endif
- @foreach($sidebarTree as $bookChild)
- <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}">
- <a href="{{ $bookChild->getUrl() }}" class="{{ $bookChild->getClassName() }} {{ $current->matches($bookChild)? 'selected' : '' }}">
- @if($bookChild->isA('chapter'))@icon('chapter')@else @icon('page')@endif{{ $bookChild->name }}
- </a>
+ @foreach($sidebarTree as $bookChild)
+ <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}">
+ @include('partials.entity-list-item-basic', ['entity' => $bookChild, 'classes' => $current->matches($bookChild)? 'selected' : ''])
- @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
- <p chapter-toggle class="text-muted @if($bookChild->matchesOrContains($current)) open @endif">
- @icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $bookChild->pages->count()) }}</span>
- </p>
- <ul class="menu sub-menu inset-list @if($bookChild->matchesOrContains($current)) open @endif">
- @foreach($bookChild->pages as $childPage)
- <li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}">
- <a href="{{ $childPage->getUrl() }}" class="page {{ $current->matches($childPage)? 'selected' : '' }}">
- @icon('page') {{ $childPage->name }}
- </a>
- </li>
- @endforeach
- </ul>
- @endif
+ @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
+ <div class="entity-list-item no-hover">
+ <span class="icon text-chapter">
+ </span>
+ <div class="content">
+ @include('chapters.child-menu', ['chapter' => $bookChild, 'current' => $current])
+ </div>
+ </div>
- </li>
- @endforeach
- </ul>
- </div>
+ @endif
+
+ </li>
+ @endforeach
+ </ul>
</div>
\ No newline at end of file
--- /dev/null
+<div class="breadcrumb-listing" dropdown breadcrumb-listing="{{ $entity->getType() }}:{{ $entity->id }}">
+ <div class="breadcrumb-listing-toggle" dropdown-toggle>
+ <div class="separator">@icon('chevron-right')</div>
+ </div>
+ <div dropdown-menu class="breadcrumb-listing-dropdown card">
+ <div class="breadcrumb-listing-search">
+ @icon('search')
+ <input autocomplete="off" type="text" name="entity-search">
+ </div>
+ @include('partials.loading-icon')
+ <div class="breadcrumb-listing-entity-list px-m"></div>
+ </div>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="breadcrumbs text-center">
+ <?php $breadcrumbCount = 0; ?>
+
+ {{-- Show top level books item --}}
+ @if (count($crumbs) > 0 && array_first($crumbs) instanceof \BookStack\Entities\Book)
+ <a href="{{ baseUrl('/books') }}" class="text-book icon-list-item outline-hover">
+ <span>@icon('books')</span>
+ <span>{{ trans('entities.books') }}</span>
+ </a>
+ <?php $breadcrumbCount++; ?>
+ @endif
+
+ {{-- Show top level shelves item --}}
+ @if (count($crumbs) > 0 && array_first($crumbs) instanceof \BookStack\Entities\Bookshelf)
+ <a href="{{ baseUrl('/shelves') }}" class="text-bookshelf icon-list-item outline-hover">
+ <span>@icon('bookshelf')</span>
+ <span>{{ trans('entities.shelves') }}</span>
+ </a>
+ <?php $breadcrumbCount++; ?>
+ @endif
+
+ @foreach($crumbs as $key => $crumb)
+ <?php $isEntity = ($crumb instanceof \BookStack\Entities\Entity); ?>
+
+ @if (is_null($crumb))
+ <?php continue; ?>
+ @endif
+ @if ($breadcrumbCount !== 0 && !$isEntity)
+ <div class="separator">@icon('chevron-right')</div>
+ @endif
+
+ @if (is_string($crumb))
+ <a href="{{ baseUrl($key) }}">
+ {{ $crumb }}
+ </a>
+ @elseif (is_array($crumb))
+ <a href="{{ baseUrl($key) }}" class="icon-list-item outline-hover">
+ <span>@icon($crumb['icon'])</span>
+ <span>{{ $crumb['text'] }}</span>
+ </a>
+ @elseif($isEntity && userCan('view', $crumb))
+ @if($breadcrumbCount > 0)
+ @include('partials.breadcrumb-listing', ['entity' => $crumb])
+ @endif
+ <a href="{{ $crumb->getUrl() }}" class="text-{{$crumb->getType()}} icon-list-item outline-hover">
+ <span>@icon($crumb->getType())</span>
+ <span>
+ {{ $crumb->getShortName() }}
+ </span>
+ </a>
+ @endif
+ <?php $breadcrumbCount++; ?>
+ @endforeach
+</div>
\ No newline at end of file
<style id="custom-styles" data-color="{{ setting('app-color') }}" data-color-light="{{ setting('app-color-light') }}">
- header, [back-to-top], .primary-background {
+ .primary-background {
background-color: {{ setting('app-color') }} !important;
}
- .faded-small, .primary-background-light {
+ .primary-background-light {
background-color: {{ setting('app-color-light') }};
}
- .button-base, .button, input[type="button"], input[type="submit"] {
+ .button.primary, .button.primary:hover, .button.primary:active, .button.primary:focus {
background-color: {{ setting('app-color') }};
border-color: {{ setting('app-color') }};
}
- .button-base:hover, .button:hover, input[type="button"]:hover, input[type="submit"]:hover, .button:focus {
- background-color: {{ setting('app-color') }};
- }
.nav-tabs a.selected, .nav-tabs .tab-item.selected {
border-bottom-color: {{ setting('app-color') }};
}
- .text-primary, p.primary, p .primary, span.primary:hover, .text-primary:hover, a, a:hover, a:focus, .text-button, .text-button:hover, .text-button:focus {
+ .text-primary, .text-primary-hover:hover, .text-primary:hover {
+ color: {{ setting('app-color') }} !important;
+ fill: {{ setting('app-color') }} !important;
+ }
+
+ a, a:hover, a:focus, .text-button, .text-button:hover, .text-button:focus {
color: {{ setting('app-color') }};
fill: {{ setting('app-color') }};
}
--- /dev/null
+<div class="mb-xl">
+ <form v-on:submit.prevent="searchBook" class="search-box flexible">
+ <input v-model="searchTerm" v-on:change="checkSearchForm" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}">
+ <button type="submit">@icon('search')</button>
+ <button v-if="searching" v-cloak class="search-box-cancel text-neg" v-on:click="clearSearch" type="button">@icon('close')</button>
+ </form>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="search-results" v-cloak v-show="searching">
+ <div class="grid half v-center">
+ <h3 class="text-muted px-none">
+ {{ trans('entities.search_results') }}
+ </h3>
+ <div class="text-right">
+ <a v-if="searching" v-on:click="clearSearch" class="button outline">{{ trans('entities.search_clear') }}</a>
+ </div>
+ </div>
+
+ <div v-if="!searchResults">
+ @include('partials.loading-icon')
+ </div>
+ <div class="book-contents" v-html="searchResults"></div>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="entity-list {{ $style ?? '' }}">
+ @if(count($entities) > 0)
+ @foreach($entities as $index => $entity)
+ @include('partials.entity-list-item-basic', ['entity' => $entity])
+ @endforeach
+ @else
+ <p class="text-muted empty-text">
+ {{ $emptyText ?? trans('common.no_items') }}
+ </p>
+ @endif
+</div>
\ No newline at end of file
--- /dev/null
+<?php $type = $entity->getType(); ?>
+<a href="{{ $entity->getUrl() }}" class="{{$type}} {{$type === 'page' && $entity->draft ? 'draft' : ''}} {{$classes ?? ''}} entity-list-item" data-entity-type="{{$type}}" data-entity-id="{{$entity->id}}">
+ <span class="icon text-{{$type}}">@icon($type)</span>
+ <div class="content">
+ <h4 class="entity-list-item-name break-text">{{ $entity->name }}</h4>
+ {{ $slot ?? '' }}
+ </div>
+</a>
\ No newline at end of file
--- /dev/null
+@component('partials.entity-list-item-basic', ['entity' => $entity])
+<div class="entity-item-snippet">
+
+ @if($showPath ?? false)
+ @if($entity->book_id)
+ <span class="text-book">{{ $entity->book->getShortName(42) }}</span>
+ @if($entity->chapter_id)
+ <span class="text-muted entity-list-item-path-sep">@icon('chevron-right')</span> <span class="text-chapter">{{ $entity->chapter->getShortName(42) }}</span>
+ @endif
+ @endif
+ @endif
+
+ <p class="text-muted break-text">{{ $entity->getExcerpt() }}</p>
+</div>
+@endcomponent
\ No newline at end of file
-<div class="entity-list @if(isset($style)){{ $style }}@endif">
+<div class="entity-list {{ $style ?? '' }}">
@if(count($entities) > 0)
@foreach($entities as $index => $entity)
- @if($entity->isA('page'))
- @include('pages/list-item', ['page' => $entity])
- @elseif($entity->isA('book'))
- @include('books/list-item', ['book' => $entity])
- @elseif($entity->isA('chapter'))
- @include('chapters/list-item', ['chapter' => $entity, 'hidePages' => true])
- @elseif($entity->isA('bookshelf'))
- @include('shelves/list-item', ['bookshelf' => $entity])
- @endif
-
- @if($index !== count($entities) - 1)
- <hr>
- @endif
-
+ @include('partials.entity-list-item', ['entity' => $entity, 'showPath' => $showPath ?? false])
@endforeach
@else
<p class="text-muted empty-text">
- {{ $emptyText or trans('common.no_items') }}
+ {{ $emptyText ?? trans('common.no_items') }}
</p>
@endif
</div>
\ No newline at end of file
--- /dev/null
+<?php
+ $selectedSort = (isset($sort) && array_key_exists($sort, $options)) ? $sort : array_keys($options)[0];
+ $order = (isset($order) && in_array($order, ['asc', 'desc'])) ? $order : 'asc';
+?>
+<div class="list-sort-container" list-sort-control>
+ <div class="list-sort-label">{{ trans('common.sort') }}</div>
+ <form action="{{ baseUrl("/settings/users/{$currentUser->id}/change-sort/{$type}") }}" method="post">
+
+ {!! csrf_field() !!}
+ {!! method_field('PATCH') !!}
+ <input type="hidden" value="{{ $selectedSort }}" name="sort">
+ <input type="hidden" value="{{ $order }}" name="order">
+
+ <div class="list-sort">
+ <div class="list-sort-type dropdown-container" dropdown>
+ <div dropdown-toggle>{{ $options[$selectedSort] }}</div>
+ <ul>
+ @foreach($options as $key => $label)
+ <li @if($key === $selectedSort) class="active" @endif><a href="#" data-sort-value="{{$key}}">{{ $label }}</a></li>
+ @endforeach
+ </ul>
+ </div>
+ <div class="list-sort-dir" data-sort-dir>
+ @if($order === 'desc')
+ @icon('sort-up')
+ @else
+ @icon('sort-down')
+ @endif
+ </div>
+ </div>
+ </form>
+</div>
\ No newline at end of file
--- /dev/null
+<div>
+ <form action="{{ baseUrl("/settings/users/{$currentUser->id}/switch-${type}-view") }}" method="POST" class="inline">
+ {!! csrf_field() !!}
+ {!! method_field('PATCH') !!}
+ <input type="hidden" value="{{ $view === 'list'? 'grid' : 'list' }}" name="view_type">
+ @if ($view === 'list')
+ <button type="submit" class="icon-list-item text-primary">
+ <span class="icon">@icon('grid')</span>
+ <span>{{ trans('common.grid_view') }}</span>
+ </button>
+ @else
+ <button type="submit" class="icon-list-item text-primary">
+ <span>@icon('list')</span>
+ <span>{{ trans('common.list_view') }}</span>
+ </button>
+ @endif
+ </form>
+</div>
\ No newline at end of file
+++ /dev/null
-<!DOCTYPE html>
-<html class="shaded">
-<head>
- <title>{{ setting('app-name') }}</title>
-
- <!-- Meta -->
- <meta name="viewport" content="width=device-width">
- <meta name="token" content="{{ csrf_token() }}">
- <meta name="base-url" content="{{ baseUrl('/') }}">
- <meta charset="utf-8">
-
- <!-- Styles and Fonts -->
- <link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
- <link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
-
- <!-- Scripts -->
- @include('partials/custom-styles')
-
- <!-- Custom user content -->
- @if(setting('app-custom-head'))
- {!! setting('app-custom-head') !!}
- @endif
-</head>
-<body class="@yield('body-class')">
-
-@include('partials.notifications')
-
-<header id="header">
- <div class="container fluid">
- <div class="row">
- <div class="col-sm-6">
-
- <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-6">
- <div class="float right">
- <div class="links text-center">
- @yield('header-buttons')
- </div>
- @if(isset($signedIn) && $signedIn)
- @include('partials._header-dropdown', ['currentUser' => $currentUser])
- @endif
- </div>
- </div>
- </div>
- </div>
-</header>
-
-<section class="container">
- @yield('content')
-</section>
-
-<script src="{{ versioned_asset('dist/app.js') }}"></script>
-</body>
-</html>
-@extends('sidebar-layout')
+@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- <div class="breadcrumbs">
- <a href="{{ baseUrl("/search?term=" . urlencode($searchTerm)) }}" class="text-button">@icon('search'){{ trans('entities.search_for_term', ['term' => $searchTerm]) }}</a>
- </div>
- </div>
-@stop
-
-@section('container-attrs')
- id="search-system"
-@stop
+@section('body')
+ <input type="hidden" name="searchTerm" value="{{$searchTerm}}">
-@section('sidebar')
- <div class="card">
- <h3>{{ trans('entities.search_filters') }}</h3>
-
- <div class="body">
- <form v-on:submit="updateSearch" v-cloak class="v-cloak anim fadeIn">
- <h6 class="text-muted">{{ trans('entities.search_content_type') }}</h6>
- <div class="form-group">
- <label class="inline checkbox text-page"><input type="checkbox" v-on:change="typeChange" v-model="search.type.page" value="page">{{ trans('entities.page') }}</label>
- <label class="inline checkbox text-chapter"><input type="checkbox" v-on:change="typeChange" v-model="search.type.chapter" value="chapter">{{ trans('entities.chapter') }}</label>
- <br>
- <label class="inline checkbox text-book"><input type="checkbox" v-on:change="typeChange" v-model="search.type.book" value="book">{{ trans('entities.book') }}</label>
- <label class="inline checkbox text-bookshelf"><input type="checkbox" v-on:change="typeChange" v-model="search.type.bookshelf" value="bookshelf">{{ trans('entities.shelf') }}</label>
- </div>
+ <div class="container" id="search-system">
- <h6 class="text-muted">{{ trans('entities.search_exact_matches') }}</h6>
- <table cellpadding="0" cellspacing="0" border="0" class="no-style">
- <tr v-for="(term, i) in search.exactTerms">
- <td style="padding: 0 12px 6px 0;">
- <input class="exact-input outline" v-on:input="exactChange" type="text" v-model="search.exactTerms[i]"></td>
- <td>
- <button type="button" class="text-neg text-button" v-on:click="removeExact(i)">
- @icon('close')
- </button>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <button type="button" class="text-button" v-on:click="addExact">
- @icon('add-circle'){{ trans('common.add') }}
- </button>
- </td>
- </tr>
- </table>
-
- <h6 class="text-muted">{{ trans('entities.search_tags') }}</h6>
- <table cellpadding="0" cellspacing="0" border="0" class="no-style">
- <tr v-for="(term, i) in search.tagTerms">
- <td style="padding: 0 12px 6px 0;">
- <input class="tag-input outline" v-on:input="tagChange" type="text" v-model="search.tagTerms[i]"></td>
- <td>
- <button type="button" class="text-neg text-button" v-on:click="removeTag(i)">
- @icon('close')
- </button>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <button type="button" class="text-button" v-on:click="addTag">
- @icon('add-circle'){{ trans('common.add') }}
- </button>
- </td>
- </tr>
- </table>
-
- @if(signedInUser())
- <h6 class="text-muted">{{ trans('entities.search_options') }}</h6>
- <label class="checkbox">
- <input type="checkbox" v-on:change="optionChange('viewed_by_me')"
- v-model="search.option.viewed_by_me" value="page">
- {{ trans('entities.search_viewed_by_me') }}
- </label>
- <label class="checkbox">
- <input type="checkbox" v-on:change="optionChange('not_viewed_by_me')"
- v-model="search.option.not_viewed_by_me" value="page">
- {{ trans('entities.search_not_viewed_by_me') }}
- </label>
- <label class="checkbox">
- <input type="checkbox" v-on:change="optionChange('is_restricted')"
- v-model="search.option.is_restricted" value="page">
- {{ trans('entities.search_permissions_set') }}
- </label>
- <label class="checkbox">
- <input type="checkbox" v-on:change="optionChange('created_by:me')"
- v-model="search.option['created_by:me']" value="page">
- {{ trans('entities.search_created_by_me') }}
- </label>
- <label class="checkbox">
- <input type="checkbox" v-on:change="optionChange('updated_by:me')"
- v-model="search.option['updated_by:me']" value="page">
- {{ trans('entities.search_updated_by_me') }}
- </label>
- @endif
-
- <h6 class="text-muted">{{ trans('entities.search_date_options') }}</h6>
- <table cellpadding="0" cellspacing="0" border="0" class="no-style form-table">
- <tr>
- <td width="200">{{ trans('entities.search_updated_after') }}</td>
- <td width="80">
- <button type="button" class="text-button" v-if="!search.dates.updated_after"
- v-on:click="enableDate('updated_after')">{{ trans('entities.search_set_date') }}</button>
-
- </td>
- </tr>
- <tr v-if="search.dates.updated_after">
- <td>
- <input v-if="search.dates.updated_after" class="tag-input"
- v-on:input="dateChange('updated_after')" type="date" v-model="search.dates.updated_after"
- pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
- </td>
- <td>
- <button v-if="search.dates.updated_after" type="button" class="text-neg text-button"
- v-on:click="dateRemove('updated_after')">
- @icon('close')
- </button>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.search_updated_before') }}</td>
- <td>
- <button type="button" class="text-button" v-if="!search.dates.updated_before"
- v-on:click="enableDate('updated_before')">{{ trans('entities.search_set_date') }}</button>
-
- </td>
- </tr>
- <tr v-if="search.dates.updated_before">
- <td>
- <input v-if="search.dates.updated_before" class="tag-input"
- v-on:input="dateChange('updated_before')" type="date" v-model="search.dates.updated_before"
- pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
- </td>
- <td>
- <button v-if="search.dates.updated_before" type="button" class="text-neg text-button"
- v-on:click="dateRemove('updated_before')">
- @icon('close')
- </button>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.search_created_after') }}</td>
- <td>
- <button type="button" class="text-button" v-if="!search.dates.created_after"
- v-on:click="enableDate('created_after')">{{ trans('entities.search_set_date') }}</button>
-
- </td>
- </tr>
- <tr v-if="search.dates.created_after">
- <td>
- <input v-if="search.dates.created_after" class="tag-input"
- v-on:input="dateChange('created_after')" type="date" v-model="search.dates.created_after"
- pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
- </td>
- <td>
- <button v-if="search.dates.created_after" type="button" class="text-neg text-button"
- v-on:click="dateRemove('created_after')">
- @icon('close')
- </button>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.search_created_before') }}</td>
- <td>
- <button type="button" class="text-button" v-if="!search.dates.created_before"
- v-on:click="enableDate('created_before')">{{ trans('entities.search_set_date') }}</button>
-
- </td>
- </tr>
- <tr v-if="search.dates.created_before">
- <td>
- <input v-if="search.dates.created_before" class="tag-input"
- v-on:input="dateChange('created_before')" type="date" v-model="search.dates.created_before"
- pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
- </td>
- <td>
- <button v-if="search.dates.created_before" type="button" class="text-neg text-button"
- v-on:click="dateRemove('created_before')">
- @icon('close')
- </button>
- </td>
- </tr>
- </table>
-
-
- <button type="submit" class="button primary">{{ trans('entities.search_update') }}</button>
- </form>
+ <div class="my-s">
+
</div>
- </div>
-@stop
-
-@section('body')
+ <div class="grid right-focus reverse-collapse gap-xl">
+ <div>
+ <div>
+ <h5>{{ trans('entities.search_filters') }}</h5>
+
+ <form v-on:submit="updateSearch" v-cloak class="v-cloak anim fadeIn">
+ <h6 class="text-muted">{{ trans('entities.search_content_type') }}</h6>
+ <div class="form-group">
+ <label class="inline checkbox text-page"><input type="checkbox" v-on:change="typeChange" v-model="search.type.page" value="page">{{ trans('entities.page') }}</label>
+ <label class="inline checkbox text-chapter"><input type="checkbox" v-on:change="typeChange" v-model="search.type.chapter" value="chapter">{{ trans('entities.chapter') }}</label>
+ <br>
+ <label class="inline checkbox text-book"><input type="checkbox" v-on:change="typeChange" v-model="search.type.book" value="book">{{ trans('entities.book') }}</label>
+ <label class="inline checkbox text-bookshelf"><input type="checkbox" v-on:change="typeChange" v-model="search.type.bookshelf" value="bookshelf">{{ trans('entities.shelf') }}</label>
+ </div>
+
+ <h6 class="text-muted">{{ trans('entities.search_exact_matches') }}</h6>
+ <table cellpadding="0" cellspacing="0" border="0" class="no-style">
+ <tr v-for="(term, i) in search.exactTerms">
+ <td style="padding: 0 12px 6px 0;">
+ <input class="exact-input outline" v-on:input="exactChange" type="text" v-model="search.exactTerms[i]"></td>
+ <td>
+ <button type="button" class="text-neg text-button" v-on:click="removeExact(i)">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <button type="button" class="text-button" v-on:click="addExact">
+ @icon('add-circle'){{ trans('common.add') }}
+ </button>
+ </td>
+ </tr>
+ </table>
+
+ <h6 class="text-muted">{{ trans('entities.search_tags') }}</h6>
+ <table cellpadding="0" cellspacing="0" border="0" class="no-style">
+ <tr v-for="(term, i) in search.tagTerms">
+ <td style="padding: 0 12px 6px 0;">
+ <input class="tag-input outline" v-on:input="tagChange" type="text" v-model="search.tagTerms[i]"></td>
+ <td>
+ <button type="button" class="text-neg text-button" v-on:click="removeTag(i)">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <button type="button" class="text-button" v-on:click="addTag">
+ @icon('add-circle'){{ trans('common.add') }}
+ </button>
+ </td>
+ </tr>
+ </table>
+
+ @if(signedInUser())
+ <h6 class="text-muted">{{ trans('entities.search_options') }}</h6>
+ <label class="checkbox">
+ <input type="checkbox" v-on:change="optionChange('viewed_by_me')"
+ v-model="search.option.viewed_by_me" value="page">
+ {{ trans('entities.search_viewed_by_me') }}
+ </label>
+ <label class="checkbox">
+ <input type="checkbox" v-on:change="optionChange('not_viewed_by_me')"
+ v-model="search.option.not_viewed_by_me" value="page">
+ {{ trans('entities.search_not_viewed_by_me') }}
+ </label>
+ <label class="checkbox">
+ <input type="checkbox" v-on:change="optionChange('is_restricted')"
+ v-model="search.option.is_restricted" value="page">
+ {{ trans('entities.search_permissions_set') }}
+ </label>
+ <label class="checkbox">
+ <input type="checkbox" v-on:change="optionChange('created_by:me')"
+ v-model="search.option['created_by:me']" value="page">
+ {{ trans('entities.search_created_by_me') }}
+ </label>
+ <label class="checkbox">
+ <input type="checkbox" v-on:change="optionChange('updated_by:me')"
+ v-model="search.option['updated_by:me']" value="page">
+ {{ trans('entities.search_updated_by_me') }}
+ </label>
+ @endif
+
+ <h6 class="text-muted">{{ trans('entities.search_date_options') }}</h6>
+ <table cellpadding="0" cellspacing="0" border="0" class="no-style form-table">
+ <tr>
+ <td width="200">{{ trans('entities.search_updated_after') }}</td>
+ <td width="80">
+ <button type="button" class="text-button" v-if="!search.dates.updated_after"
+ v-on:click="enableDate('updated_after')">{{ trans('entities.search_set_date') }}</button>
+
+ </td>
+ </tr>
+ <tr v-if="search.dates.updated_after">
+ <td>
+ <input v-if="search.dates.updated_after" class="tag-input"
+ v-on:input="dateChange('updated_after')" type="date" v-model="search.dates.updated_after"
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
+ </td>
+ <td>
+ <button v-if="search.dates.updated_after" type="button" class="text-neg text-button"
+ v-on:click="dateRemove('updated_after')">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <td>{{ trans('entities.search_updated_before') }}</td>
+ <td>
+ <button type="button" class="text-button" v-if="!search.dates.updated_before"
+ v-on:click="enableDate('updated_before')">{{ trans('entities.search_set_date') }}</button>
+
+ </td>
+ </tr>
+ <tr v-if="search.dates.updated_before">
+ <td>
+ <input v-if="search.dates.updated_before" class="tag-input"
+ v-on:input="dateChange('updated_before')" type="date" v-model="search.dates.updated_before"
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
+ </td>
+ <td>
+ <button v-if="search.dates.updated_before" type="button" class="text-neg text-button"
+ v-on:click="dateRemove('updated_before')">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <td>{{ trans('entities.search_created_after') }}</td>
+ <td>
+ <button type="button" class="text-button" v-if="!search.dates.created_after"
+ v-on:click="enableDate('created_after')">{{ trans('entities.search_set_date') }}</button>
+
+ </td>
+ </tr>
+ <tr v-if="search.dates.created_after">
+ <td>
+ <input v-if="search.dates.created_after" class="tag-input"
+ v-on:input="dateChange('created_after')" type="date" v-model="search.dates.created_after"
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
+ </td>
+ <td>
+ <button v-if="search.dates.created_after" type="button" class="text-neg text-button"
+ v-on:click="dateRemove('created_after')">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <td>{{ trans('entities.search_created_before') }}</td>
+ <td>
+ <button type="button" class="text-button" v-if="!search.dates.created_before"
+ v-on:click="enableDate('created_before')">{{ trans('entities.search_set_date') }}</button>
+
+ </td>
+ </tr>
+ <tr v-if="search.dates.created_before">
+ <td>
+ <input v-if="search.dates.created_before" class="tag-input"
+ v-on:input="dateChange('created_before')" type="date" v-model="search.dates.created_before"
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
+ </td>
+ <td>
+ <button v-if="search.dates.created_before" type="button" class="text-neg text-button"
+ v-on:click="dateRemove('created_before')">
+ @icon('close')
+ </button>
+ </td>
+ </tr>
+ </table>
+
+
+ <button type="submit" class="button primary">{{ trans('entities.search_update') }}</button>
+ </form>
- <div class="container small" v-pre>
- <input type="hidden" name="searchTerm" value="{{$searchTerm}}">
+ </div>
+ </div>
+ <div>
+ <div v-pre class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.search_results') }}</h1>
+ <h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
+ <div class="book-contents">
+ @include('partials.entity-list', ['entities' => $entities, 'showPath' => true])
+ </div>
+ @if($hasNextPage)
+ <div class="text-right mt-m">
+ <a href="{{ $nextPageLink }}" class="button outline">{{ trans('entities.search_more') }}</a>
+ </div>
+ @endif
+ </div>
+ </div>
+ </div>
- <h1>{{ trans('entities.search_results') }}</h1>
- <h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
- @include('partials/entity-list', ['entities' => $entities])
- @if ($hasNextPage)
- <a href="{{ $nextPageLink }}" class="button">{{ trans('entities.search_more') }}</a>
- @endif
</div>
@stop
@if(count($pages) > 0)
@foreach($pages as $pageIndex => $page)
<div class="anim searchResult" style="animation-delay: {{$pageIndex*50 . 'ms'}};">
- @include('pages/list-item', ['page' => $page])
+ @include('pages.list-item', ['page' => $page])
<hr>
</div>
@endforeach
<div class="page-list">
@foreach($chapters as $chapterIndex => $chapter)
<div class="anim searchResult" style="animation-delay: {{($chapterIndex+count($pages))*50 . 'ms'}};">
- @include('chapters/list-item', ['chapter' => $chapter, 'hidePages' => true])
+ @include('chapters.list-item', ['chapter' => $chapter, 'hidePages' => true])
<hr>
</div>
@endforeach
-<div class="entity-list @if(isset($style)){{ $style }}@endif">
+<div class="entity-list">
@if(count($entities) > 0)
@foreach($entities as $index => $entity)
- @if($entity->isA('page'))
- @include('pages/list-item', ['page' => $entity, 'showPath' => true])
- @elseif($entity->isA('book'))
- @include('books/list-item', ['book' => $entity])
- @elseif($entity->isA('chapter'))
- @include('chapters/list-item', ['chapter' => $entity, 'hidePages' => true, 'showPath' => true])
- @endif
+ @include('partials.entity-list-item', ['entity' => $entity, 'showPath' => true])
@if($index !== count($entities) - 1)
<hr>
@endif
@endforeach
@else
- <p class="text-muted">
+ <p class="text-muted text-large p-xl">
{{ trans('common.no_items') }}
</p>
@endif
+++ /dev/null
-@extends('base')
-
-@section('content')
-
- <div class="faded-small toolbar">
- <div class="container">
- <div class="row">
- <div class="col-sm-12 faded">
- <div class="breadcrumbs">
- <a href="{{ baseUrl("/search/all?term={$searchTerm}") }}" class="text-button">@icon('search'){{ $searchTerm }}</a>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="container">
- <div class="row">
-
- <div class="col-sm-7">
- <h1>{{ $title }}</h1>
- @include('partials.entity-list', ['entities' => $entities, 'style' => 'detailed'])
- {!! $entities->links() !!}
- </div>
-
- </div>
- </div>
-@stop
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'settings'])
-@stop
-
@section('body')
-<div class="container small">
+ <div class="container small">
- <div class="text-right text-muted container">
- <br>
- BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
- </div>
+ <div class="grid left-focus v-center no-row-gap">
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'settings'])
+ </div>
+ <div class="text-right mb-l px-m">
+ <br>
+ BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
+ </div>
+ </div>
- <div class="card">
- <h3>@icon('settings') {{ trans('settings.app_settings') }}</h3>
- <div class="body">
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.app_features_security') }}</h2>
<form action="{{ baseUrl("/settings") }}" method="POST">
- {!! csrf_field() !!}
- <div class="row">
+ {!! csrf_field() !!}
- <div class="col-md-6">
- <div class="form-group">
- <label for="setting-app-name">{{ trans('settings.app_name') }}</label>
- <p class="small">{{ trans('settings.app_name_desc') }}</p>
- <input type="text" value="{{ setting('app-name', 'BookStack') }}" name="setting-app-name" id="setting-app-name">
- </div>
- <div class="form-group">
- <label>{{ trans('settings.app_name_header') }}</label>
- @include('components.toggle-switch', ['name' => 'setting-app-name-header', 'value' => setting('app-name-header')])
+ <div class="setting-list">
+
+
+ <div class="grid half gap-xl">
+ <div>
+ <label for="setting-app-public" class="setting-list-label">{{ trans('settings.app_public_access') }}</label>
+ <p class="small">{!! trans('settings.app_public_access_desc') !!}</p>
+ @if(userCan('users-manage'))
+ <p class="small mb-none">
+ <a href="{{ baseUrl($guestUser->getEditUrl()) }}">{!! trans('settings.app_public_access_desc_guest') !!}</a>
+ </p>
+ @endif
</div>
- <div class="form-group">
- <label for="setting-app-public">{{ trans('settings.app_public_viewing') }}</label>
- @include('components.toggle-switch', ['name' => 'setting-app-public', 'value' => setting('app-public')])
+ <div>
+ @include('components.toggle-switch', [
+ 'name' => 'setting-app-public',
+ 'value' => setting('app-public'),
+ 'label' => trans('settings.app_public_access_toggle'),
+ ])
</div>
- <div class="form-group">
- <label>{{ trans('settings.app_secure_images') }}</label>
+ </div>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.app_secure_images') }}</label>
<p class="small">{{ trans('settings.app_secure_images_desc') }}</p>
- @include('components.toggle-switch', ['name' => 'setting-app-secure-images', 'value' => setting('app-secure-images')])
</div>
- <div class="form-group">
- <label>{{ trans('settings.app_disable_comments') }}</label>
- <p class="small">{{ trans('settings.app_disable_comments_desc') }}</p>
- @include('components.toggle-switch', ['name' => 'setting-app-disable-comments', 'value' => setting('app-disable-comments')])
+ <div>
+ @include('components.toggle-switch', [
+ 'name' => 'setting-app-secure-images',
+ 'value' => setting('app-secure-images'),
+ 'label' => trans('settings.app_secure_images_toggle'),
+ ])
+ </div>
+ </div>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.app_disable_comments') }}</label>
+ <p class="small">{!! trans('settings.app_disable_comments_desc') !!}</p>
+ </div>
+ <div>
+ @include('components.toggle-switch', [
+ 'name' => 'setting-app-disable-comments',
+ 'value' => setting('app-disable-comments'),
+ 'label' => trans('settings.app_disable_comments_toggle'),
+ ])
+ </div>
+ </div>
+
+
+ </div>
+
+ <div class="form-group text-right">
+ <button type="submit" class="button primary">{{ trans('settings.settings_save') }}</button>
+ </div>
+ </form>
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.app_customization') }}</h2>
+ <form action="{{ baseUrl("/settings") }}" method="POST">
+ {!! csrf_field() !!}
+
+ <div class="setting-list">
+
+ <div class="grid half gap-xl">
+ <div>
+ <label for="setting-app-name" class="setting-list-label">{{ trans('settings.app_name') }}</label>
+ <p class="small">{{ trans('settings.app_name_desc') }}</p>
+ </div>
+ <div>
+ <input type="text" value="{{ setting('app-name', 'BookStack') }}" name="setting-app-name" id="setting-app-name">
+ @include('components.toggle-switch', [
+ 'name' => 'setting-app-name-header',
+ 'value' => setting('app-name-header'),
+ 'label' => trans('settings.app_name_header'),
+ ])
</div>
- <div class="form-group">
- <label for="setting-app-editor">{{ trans('settings.app_editor') }}</label>
+ </div>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.app_editor') }}</label>
<p class="small">{{ trans('settings.app_editor_desc') }}</p>
+ </div>
+ <div>
<select name="setting-app-editor" id="setting-app-editor">
<option @if(setting('app-editor') === 'wysiwyg') selected @endif value="wysiwyg">WYSIWYG</option>
<option @if(setting('app-editor') === 'markdown') selected @endif value="markdown">Markdown</option>
</div>
</div>
- <div class="col-md-6">
- <div class="form-group" id="logo-control">
- <label for="setting-app-logo">{{ trans('settings.app_logo') }}</label>
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.app_logo') }}</label>
<p class="small">{!! trans('settings.app_logo_desc') !!}</p>
-
+ </div>
+ <div>
@include('components.image-picker', [
- 'resizeHeight' => '43',
- 'resizeWidth' => '200',
- 'showRemove' => true,
- 'defaultImage' => baseUrl('/logo.png'),
- 'currentImage' => setting('app-logo'),
- 'name' => 'setting-app-logo',
- 'imageClass' => 'logo-image',
- 'currentId' => false
- ])
-
+ 'resizeHeight' => '43',
+ 'resizeWidth' => '200',
+ 'showRemove' => true,
+ 'defaultImage' => baseUrl('/logo.png'),
+ 'currentImage' => setting('app-logo'),
+ 'name' => 'setting-app-logo',
+ 'imageClass' => 'logo-image',
+ 'currentId' => false
+ ])
</div>
- <div class="form-group" id="color-control">
- <label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label>
+ </div>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.app_primary_color') }}</label>
<p class="small">{!! trans('settings.app_primary_color_desc') !!}</p>
+ </div>
+ <div>
<input type="text" value="{{ setting('app-color') }}" name="setting-app-color" id="setting-app-color" placeholder="#0288D1">
<input type="hidden" value="{{ setting('app-color-light') }}" name="setting-app-color-light" id="setting-app-color-light">
</div>
- <div homepage-control class="form-group" id="homepage-control">
- <label for="setting-app-homepage">{{ trans('settings.app_homepage') }}</label>
- <p class="small">{{ trans('settings.app_homepage_desc') }}</p>
+ </div>
+ <div homepage-control id="homepage-control" class="grid half gap-xl">
+ <div>
+ <label for="setting-app-homepage" class="setting-list-label">{{ trans('settings.app_homepage') }}</label>
+ <p class="small">{{ trans('settings.app_homepage_desc') }}</p>
+ </div>
+ <div>
<select name="setting-app-homepage-type" id="setting-app-homepage-type">
<option @if(setting('app-homepage-type') === 'default') selected @endif value="default">{{ trans('common.default') }}</option>
<option @if(setting('app-homepage-type') === 'books') selected @endif value="books">{{ trans('entities.books') }}</option>
<option @if(setting('app-homepage-type') === 'page') selected @endif value="page">{{ trans('entities.pages_specific') }}</option>
</select>
- <br><br>
-
- <div page-picker-container style="display: none;">
+ <div page-picker-container style="display: none;" class="mt-m">
@include('components.page-picker', ['name' => 'setting-app-homepage', 'placeholder' => trans('settings.app_homepage_select'), 'value' => setting('app-homepage')])
</div>
</div>
</div>
- </div>
- <div class="form-group">
- <label for="setting-app-custom-head">{{ trans('settings.app_custom_html') }}</label>
- <p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
- <textarea class="simple-code-input" name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea>
+ <div>
+ <label for="setting-app-custom-head" class="setting-list-label">{{ trans('settings.app_custom_html') }}</label>
+ <p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
+ <textarea name="setting-app-custom-head" id="setting-app-custom-head" class="simple-code-input mt-m">{{ setting('app-custom-head', '') }}</textarea>
+ </div>
+
+
</div>
<div class="form-group text-right">
- <button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('settings.settings_save') }}</button>
</div>
</form>
</div>
- </div>
-
- <p> </p>
- <div class="card">
- <h3>@icon('users-add') {{ trans('settings.reg_settings') }}</h3>
- <div class="body">
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.reg_settings') }}</h2>
<form action="{{ baseUrl("/settings") }}" method="POST">
{!! csrf_field() !!}
- <div class="row">
- <div class="col-md-6">
- <div class="form-group">
- <label for="setting-registration-enabled">{{ trans('settings.reg_allow') }}</label>
- @include('components.toggle-switch', ['name' => 'setting-registration-enabled', 'value' => setting('registration-enabled')])
+ <div class="setting-list">
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.reg_enable') }}</label>
+ <p class="small">{!! trans('settings.reg_enable_desc') !!}</p>
</div>
- <div class="form-group">
+ <div>
+ @include('components.toggle-switch', [
+ 'name' => 'setting-registration-enabled',
+ 'value' => setting('registration-enabled'),
+ 'label' => trans('settings.reg_enable_toggle')
+ ])
+
<label for="setting-registration-role">{{ trans('settings.reg_default_role') }}</label>
<select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
@foreach(\BookStack\Auth\Role::all() as $role)
@endforeach
</select>
</div>
- <div class="form-group">
- <label for="setting-registration-confirmation">{{ trans('settings.reg_confirm_email') }}</label>
- <p class="small">{{ trans('settings.reg_confirm_email_desc') }}</p>
- @include('components.toggle-switch', ['name' => 'setting-registration-confirmation', 'value' => setting('registration-confirmation')])
- </div>
</div>
- <div class="col-md-6">
- <div class="form-group">
- <label for="setting-registration-restrict">{{ trans('settings.reg_confirm_restrict_domain') }}</label>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label for="setting-registration-restrict" class="setting-list-label">{{ trans('settings.reg_confirm_restrict_domain') }}</label>
<p class="small">{!! trans('settings.reg_confirm_restrict_domain_desc') !!}</p>
+ </div>
+ <div>
<input type="text" id="setting-registration-restrict" name="setting-registration-restrict" placeholder="{{ trans('settings.reg_confirm_restrict_domain_placeholder') }}" value="{{ setting('registration-restrict', '') }}">
</div>
</div>
+
+ <div class="grid half gap-xl">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.reg_email_confirmation') }}</label>
+ <p class="small">{{ trans('settings.reg_confirm_email_desc') }}</p>
+ </div>
+ <div>
+ @include('components.toggle-switch', [
+ 'name' => 'setting-registration-confirmation',
+ 'value' => setting('registration-confirmation'),
+ 'label' => trans('settings.reg_email_confirmation_toggle')
+ ])
+ </div>
+ </div>
+
</div>
<div class="form-group text-right">
- <button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('settings.settings_save') }}</button>
</div>
</form>
</div>
- </div>
-
-</div>
-
-@include('components.image-manager', ['imageType' => 'system'])
-@include('components.entity-selector-popup', ['entityTypes' => 'page'])
+ </div>
+ @include('components.image-manager', ['imageType' => 'system'])
+ @include('components.entity-selector-popup', ['entityTypes' => 'page'])
@stop
@section('scripts')
$('#setting-app-color').colorPicker({
opacity: false,
renderCallback: function($elm, toggled) {
- var hexVal = '#' + this.color.colors.HEX;
- var rgb = this.color.colors.RND.rgb;
- var rgbLightVal = 'rgba('+ [rgb.r, rgb.g, rgb.b, '0.15'].join(',') +')';
+ const hexVal = '#' + this.color.colors.HEX;
+ const rgb = this.color.colors.RND.rgb;
+ const rgbLightVal = 'rgba('+ [rgb.r, rgb.g, rgb.b, '0.15'].join(',') +')';
// Set textbox color to hex color code.
- var isEmpty = $.trim($elm.val()).length === 0;
+ const isEmpty = $.trim($elm.val()).length === 0;
if (!isEmpty) $elm.val(hexVal);
$('#setting-app-color-light').val(isEmpty ? '' : rgbLightVal);
- var customStyles = document.getElementById('custom-styles');
- var oldColor = customStyles.getAttribute('data-color');
- var oldColorLight = customStyles.getAttribute('data-color-light');
+ const customStyles = document.getElementById('custom-styles');
+ const oldColor = customStyles.getAttribute('data-color');
+ const oldColorLight = customStyles.getAttribute('data-color-light');
customStyles.innerHTML = customStyles.innerHTML.split(oldColor).join(hexVal);
customStyles.innerHTML = customStyles.innerHTML.split(oldColorLight).join(rgbLightVal);
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'maintenance'])
-@stop
-
@section('body')
<div class="container small">
- <div class="text-right text-muted container">
- <br>
- BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
+ <div class="grid left-focus v-center no-row-gap">
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'maintenance'])
+ </div>
+ <div class="text-right mb-l px-m">
+ <br>
+ BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
+ </div>
</div>
- <div class="card" id="image-cleanup">
- <h3>@icon('images') {{ trans('settings.maint_image_cleanup') }}</h3>
- <div class="body">
- <div class="row">
- <div class="col-sm-6">
- <p class="small muted">{{ trans('settings.maint_image_cleanup_desc') }}</p>
- </div>
- <div class="col-sm-6">
- <form method="POST" action="{{ baseUrl('/settings/maintenance/cleanup-images') }}">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
- <div>
- @if(session()->has('cleanup-images-warning'))
- <p class="text neg">
- {{ session()->get('cleanup-images-warning') }}
- </p>
- <input type="hidden" name="ignore_revisions" value="{{ session()->getOldInput('ignore_revisions', 'false') }}">
- <input type="hidden" name="confirm" value="true">
- @else
- <label>
- <input type="checkbox" name="ignore_revisions" value="true">
- {{ trans('settings.maint_image_cleanup_ignore_revisions') }}
- </label>
- @endif
- </div>
- <button class="button outline">{{ trans('settings.maint_image_cleanup_run') }}</button>
- </form>
- </div>
+ <div id="image-cleanup" class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.maint_image_cleanup') }}</h2>
+ <div class="grid half gap-xl">
+ <div>
+ <p class="small text-muted">{{ trans('settings.maint_image_cleanup_desc') }}</p>
+ </div>
+ <div>
+ <form method="POST" action="{{ baseUrl('/settings/maintenance/cleanup-images') }}">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
+ <div>
+ @if(session()->has('cleanup-images-warning'))
+ <p class="text-neg">
+ {{ session()->get('cleanup-images-warning') }}
+ </p>
+ <input type="hidden" name="ignore_revisions" value="{{ session()->getOldInput('ignore_revisions', 'false') }}">
+ <input type="hidden" name="confirm" value="true">
+ @else
+ <label>
+ <input type="checkbox" name="ignore_revisions" value="true">
+ {{ trans('settings.maint_image_cleanup_ignore_revisions') }}
+ </label>
+ @endif
+ </div>
+ <button class="button outline">{{ trans('settings.maint_image_cleanup_run') }}</button>
+ </form>
</div>
</div>
</div>
-<div class="col-md-12 setting-nav nav-tabs">
+<div class="active-link-list">
@if($currentUser->can('settings-manage'))
- <a href="{{ baseUrl('/settings') }}" @if($selected == 'settings') class="selected text-button" @endif>@icon('settings'){{ trans('settings.settings') }}</a>
- <a href="{{ baseUrl('/settings/maintenance') }}" @if($selected == 'maintenance') class="selected text-button" @endif>@icon('spanner'){{ trans('settings.maint') }}</a>
+ <a href="{{ baseUrl('/settings') }}" @if($selected == 'settings') class="active" @endif>@icon('settings'){{ trans('settings.settings') }}</a>
+ <a href="{{ baseUrl('/settings/maintenance') }}" @if($selected == 'maintenance') class="active" @endif>@icon('spanner'){{ trans('settings.maint') }}</a>
@endif
@if($currentUser->can('users-manage'))
- <a href="{{ baseUrl('/settings/users') }}" @if($selected == 'users') class="selected text-button" @endif>@icon('users'){{ trans('settings.users') }}</a>
+ <a href="{{ baseUrl('/settings/users') }}" @if($selected == 'users') class="active" @endif>@icon('users'){{ trans('settings.users') }}</a>
@endif
@if($currentUser->can('user-roles-manage'))
- <a href="{{ baseUrl('/settings/roles') }}" @if($selected == 'roles') class="selected text-button" @endif>@icon('lock-open'){{ trans('settings.roles') }}</a>
+ <a href="{{ baseUrl('/settings/roles') }}" @if($selected == 'roles') class="active" @endif>@icon('lock-open'){{ trans('settings.roles') }}</a>
@endif
</div>
\ No newline at end of file
-<input type="checkbox" name="permissions[{{ $permission }}]"
- @if(old('permissions'.$permission, false)|| (!old('display_name', false) && (isset($role) && $role->hasPermission($permission)))) checked="checked" @endif
- value="true">
\ No newline at end of file
+
+@include('components.custom-checkbox', [
+ 'name' => 'permissions[' . $permission . ']',
+ 'value' => 'true',
+ 'checked' => old('permissions'.$permission, false)|| (!old('display_name', false) && (isset($role) && $role->hasPermission($permission))),
+ 'label' => $label
+])
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'roles'])
-@stop
-
@section('body')
- <form action="{{ baseUrl("/settings/roles/new") }}" method="POST">
- <div class="container">
- <div class="row">
- @include('settings/roles/form', ['title' => trans('settings.role_create'), 'icon' => 'plus'])
- </div>
+ <div class="container small">
+
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'roles'])
</div>
- </form>
+
+ <form action="{{ baseUrl("/settings/roles/new") }}" method="POST">
+ @include('settings.roles.form', ['title' => trans('settings.role_create')])
+ </form>
+ </div>
@stop
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'roles'])
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ trans('settings.role_delete') }}</h3>
- <div class="body">
- <p>{{ trans('settings.role_delete_confirm', ['roleName' => $role->display_name]) }}</p>
-
- <form action="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
-
- @if($role->users->count() > 0)
- <div class="form-group">
- <p>{{ trans('settings.role_delete_users_assigned', ['userCount' => $role->users->count()]) }}</p>
- @include('form/role-select', ['options' => $roles, 'name' => 'migration_role_id'])
- </div>
- @endif
- <p class="text-neg">{{ trans('settings.role_delete_sure') }}</p>
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'roles'])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading"> {{ trans('settings.role_delete') }}</h1>
+
+ <p>{{ trans('settings.role_delete_confirm', ['roleName' => $role->display_name]) }}</p>
+
+ <form action="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" method="POST">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="DELETE">
+
+ @if($role->users->count() > 0)
<div class="form-group">
- <a href="{{ baseUrl("/settings/roles/{$role->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
+ <p>{{ trans('settings.role_delete_users_assigned', ['userCount' => $role->users->count()]) }}</p>
+ @include('form.role-select', ['options' => $roles, 'name' => 'migration_role_id'])
+ </div>
+ @endif
+
+ <div class="grid half v-center">
+ <div>
+ <p class="text-neg">
+ <strong>{{ trans('settings.role_delete_sure') }}</strong>
+ </p>
</div>
- </form>
- </div>
+ <div>
+ <div class="form-group text-right">
+ <a href="{{ baseUrl("/settings/roles/{$role->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
+ </div>
+ </div>
+ </div>
+
+
+ </form>
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'roles'])
-@stop
-
@section('body')
- <form action="{{ baseUrl("/settings/roles/{$role->id}") }}" method="POST">
- <input type="hidden" name="_method" value="PUT">
- <div class="container">
- <div class="row">
- @include('settings/roles/form', ['model' => $role, 'title' => trans('settings.role_edit'), 'icon' => 'edit'])
- </div>
+ <div class="container small">
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'roles'])
</div>
- </form>
+
+ <form action="{{ baseUrl("/settings/roles/{$role->id}") }}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('settings.roles.form', ['model' => $role, 'title' => trans('settings.role_edit'), 'icon' => 'edit'])
+ </form>
+ </div>
+
@stop
{!! csrf_field() !!}
-<div class="col-md-9">
- <div class="card">
- <h3>@icon($icon) {{$title}}</h3>
- <div class="body">
- <div class="row">
- <div class="col-md-5">
- <h5>{{ trans('settings.role_details') }}</h5>
- <div class="form-group">
- <label for="name">{{ trans('settings.role_name') }}</label>
- @include('form/text', ['name' => 'display_name'])
- </div>
- <div class="form-group">
- <label for="name">{{ trans('settings.role_desc') }}</label>
- @include('form/text', ['name' => 'description'])
- </div>
+<div class="card content-wrap">
+ <h1 class="list-heading">{{ $title }}</h1>
- @if(config('auth.method') === 'ldap')
- <div class="form-group">
- <label for="name">{{ trans('settings.role_external_auth_id') }}</label>
- @include('form/text', ['name' => 'external_auth_id'])
- </div>
- @endif
+ <div class="setting-list">
- <h5>{{ trans('settings.role_system') }}</h5>
- <label>@include('settings/roles/checkbox', ['permission' => 'users-manage']) {{ trans('settings.role_manage_users') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) {{ trans('settings.role_manage_roles') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) {{ trans('settings.role_manage_entity_permissions') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-own']) {{ trans('settings.role_manage_own_entity_permissions') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'settings-manage']) {{ trans('settings.role_manage_settings') }}</label>
+ <div class="grid half">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.role_details') }}</label>
+ </div>
+ <div>
+ <div class="form-group">
+ <label for="name">{{ trans('settings.role_name') }}</label>
+ @include('form.text', ['name' => 'display_name'])
+ </div>
+ <div class="form-group">
+ <label for="name">{{ trans('settings.role_desc') }}</label>
+ @include('form.text', ['name' => 'description'])
</div>
- <div class="col-md-6">
-
- <h5>{{ trans('settings.role_asset') }}</h5>
- <p>{{ trans('settings.role_asset_desc') }}</p>
-
- @if (isset($role) && $role->system_name === 'admin')
- <p>{{ trans('settings.role_asset_admins') }}</p>
- @endif
+ @if(config('auth.method') === 'ldap')
+ <div class="form-group">
+ <label for="name">{{ trans('settings.role_external_auth_id') }}</label>
+ @include('form.text', ['name' => 'external_auth_id'])
+ </div>
+ @endif
+ </div>
+ </div>
- <table class="table">
- <tr>
- <th width="20%"></th>
- <th width="20%">{{ trans('common.create') }}</th>
- <th width="20%">{{ trans('common.view') }}</th>
- <th width="20%">{{ trans('common.edit') }}</th>
- <th width="20%">{{ trans('common.delete') }}</th>
- </tr>
- <tr>
- <td>{{ trans('entities.shelves_long') }}</td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-create-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-view-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-view-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'bookshelf-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.books') }}</td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-create-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-view-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-view-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'book-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.chapters') }}</td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-create-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-create-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-view-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-view-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'chapter-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.pages') }}</td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-create-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-create-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-view-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-view-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'page-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.images') }}</td>
- <td>@include('settings/roles/checkbox', ['permission' => 'image-create-all'])</td>
- <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'image-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'image-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'image-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'image-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.attachments') }}</td>
- <td>@include('settings/roles/checkbox', ['permission' => 'attachment-create-all'])</td>
- <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'attachment-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'attachment-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'attachment-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'attachment-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- <tr>
- <td>{{ trans('entities.comments') }}</td>
- <td>@include('settings/roles/checkbox', ['permission' => 'comment-create-all'])</td>
- <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'comment-update-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'comment-update-all']) {{ trans('settings.role_all') }}</label>
- </td>
- <td>
- <label>@include('settings/roles/checkbox', ['permission' => 'comment-delete-own']) {{ trans('settings.role_own') }}</label>
- <label>@include('settings/roles/checkbox', ['permission' => 'comment-delete-all']) {{ trans('settings.role_all') }}</label>
- </td>
- </tr>
- </table>
- </div>
+ <div class="grid half" permissions-table>
+ <div>
+ <label class="setting-list-label">{{ trans('settings.role_system') }}</label>
+ <a href="#" permissions-table-toggle-all class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
</div>
- <div class="form-group text-right">
- <a href="{{ baseUrl("/settings/roles") }}" class="button outline">{{ trans('common.cancel') }}</a>
- @if (isset($role) && $role->id)
- <a href="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" class="button neg">{{ trans('settings.role_delete') }}</a>
- @endif
- <button type="submit" class="button pos">{{ trans('settings.role_save') }}</button>
+ <div class="toggle-switch-list">
+ <div>@include('settings.roles.checkbox', ['permission' => 'users-manage', 'label' => trans('settings.role_manage_users')])</div>
+ <div>@include('settings.roles.checkbox', ['permission' => 'user-roles-manage', 'label' => trans('settings.role_manage_roles')])</div>
+ <div>@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-all', 'label' => trans('settings.role_manage_entity_permissions')])</div>
+ <div>@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-own', 'label' => trans('settings.role_manage_own_entity_permissions')])</div>
+ <div>@include('settings.roles.checkbox', ['permission' => 'settings-manage', 'label' => trans('settings.role_manage_settings')])</div>
</div>
</div>
+
+ <div>
+ <label class="setting-list-label">{{ trans('settings.role_asset') }}</label>
+ <p>{{ trans('settings.role_asset_desc') }}</p>
+
+ @if (isset($role) && $role->system_name === 'admin')
+ <p class="text-warn">{{ trans('settings.role_asset_admins') }}</p>
+ @endif
+
+ <table permissions-table class="table toggle-switch-list compact permissions-table">
+ <tr>
+ <th width="20%">
+ <a href="#" permissions-table-toggle-all class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </th>
+ <th width="20%" permissions-table-toggle-all-in-column>{{ trans('common.create') }}</th>
+ <th width="20%" permissions-table-toggle-all-in-column>{{ trans('common.view') }}</th>
+ <th width="20%" permissions-table-toggle-all-in-column>{{ trans('common.edit') }}</th>
+ <th width="20%" permissions-table-toggle-all-in-column>{{ trans('common.delete') }}</th>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.shelves_long') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-create-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-view-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-view-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'bookshelf-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.books') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'book-create-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'book-view-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'book-view-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'book-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'book-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'book-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'book-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.chapters') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-create-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-create-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-view-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-view-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'chapter-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.pages') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'page-create-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'page-create-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'page-view-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'page-view-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'page-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'page-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'page-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'page-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.images') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>@include('settings.roles.checkbox', ['permission' => 'image-create-all', 'label' => ''])</td>
+ <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'image-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'image-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'image-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'image-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.attachments') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>@include('settings.roles.checkbox', ['permission' => 'attachment-create-all', 'label' => ''])</td>
+ <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'attachment-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'attachment-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'attachment-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'attachment-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div>{{ trans('entities.comments') }}</div>
+ <a href="#" permissions-table-toggle-all-in-row class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
+ </td>
+ <td>@include('settings.roles.checkbox', ['permission' => 'comment-create-all', 'label' => ''])</td>
+ <td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'comment-update-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'comment-update-all', 'label' => trans('settings.role_all')])
+ </td>
+ <td>
+ @include('settings.roles.checkbox', ['permission' => 'comment-delete-own', 'label' => trans('settings.role_own')])
+ <br>
+ @include('settings.roles.checkbox', ['permission' => 'comment-delete-all', 'label' => trans('settings.role_all')])
+ </td>
+ </tr>
+ </table>
+ </div>
</div>
+
+ <div class="form-group text-right">
+ <a href="{{ baseUrl("/settings/roles") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ @if (isset($role) && $role->id)
+ <a href="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" class="button outline">{{ trans('settings.role_delete') }}</a>
+ @endif
+ <button type="submit" class="button primary">{{ trans('settings.role_save') }}</button>
+ </div>
+
</div>
-<div class="col-md-3">
- <div class="card">
- <h3>@icon('users') {{ trans('settings.role_users') }}</h3>
- <div class="body">
- @if(isset($role) && count($role->users) > 0)
- <table class="list-table">
- @foreach($role->users as $user)
- <tr>
- <td style="line-height: 0;"><img class="avatar small" src="{{ $user->getAvatar(40) }}" alt="{{ $user->name }}"></td>
- <td>
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- <a href="{{ baseUrl("/settings/users/{$user->id}") }}">
- @endif
- {{ $user->name }}
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- </a>
+
+<div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.role_users') }}</h2>
+ @if(isset($role) && count($role->users) > 0)
+ <div class="grid third">
+ @foreach($role->users as $user)
+ <div class="user-list-item">
+ <div>
+ <img class="avatar small" src="{{ $user->getAvatar(40) }}" alt="{{ $user->name }}">
+ </div>
+ <div>
+ @if(userCan('users-manage') || $currentUser->id == $user->id)
+ <a href="{{ baseUrl("/settings/users/{$user->id}") }}">
@endif
- </td>
- </tr>
- @endforeach
- </table>
- @else
- <p class="text-muted">
- {{ trans('settings.role_users_none') }}
- </p>
- @endif
+ {{ $user->name }}
+ @if(userCan('users-manage') || $currentUser->id == $user->id)
+ </a>
+ @endif
+ </div>
+ </div>
+ @endforeach
</div>
- </div>
+ @else
+ <p class="text-muted">
+ {{ trans('settings.role_users_none') }}
+ </p>
+ @endif
</div>
\ No newline at end of file
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'roles'])
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('lock-open') {{ trans('settings.role_user_roles') }}</h3>
- <div class="body">
- <table class="table">
- <tr>
- <th>{{ trans('settings.role_name') }}</th>
- <th></th>
- <th class="text-center">{{ trans('settings.users') }}</th>
- </tr>
- @foreach($roles as $role)
- <tr>
- <td><a href="{{ baseUrl("/settings/roles/{$role->id}") }}">{{ $role->display_name }}</a></td>
- <td>{{ $role->description }}</td>
- <td class="text-center">{{ $role->users->count() }}</td>
- </tr>
- @endforeach
- </table>
-
- <div class="form-group">
- <a href="{{ baseUrl("/settings/roles/new") }}" class="button pos">{{ trans('settings.role_create') }}</a>
+
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'roles'])
+ </div>
+
+ <div class="card content-wrap auto-height">
+
+ <div class="grid half v-center">
+ <h1 class="list-heading">{{ trans('settings.role_user_roles') }}</h1>
+
+ <div class="text-right">
+ <a href="{{ baseUrl("/settings/roles/new") }}" class="button outline">{{ trans('settings.role_create') }}</a>
</div>
</div>
+
+ <table class="table">
+ <tr>
+ <th>{{ trans('settings.role_name') }}</th>
+ <th></th>
+ <th class="text-center">{{ trans('settings.users') }}</th>
+ </tr>
+ @foreach($roles as $role)
+ <tr>
+ <td><a href="{{ baseUrl("/settings/roles/{$role->id}") }}">{{ $role->display_name }}</a></td>
+ <td>{{ $role->description }}</td>
+ <td class="text-center">{{ $role->users->count() }}</td>
+ </tr>
+ @endforeach
+ </table>
+
+
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-8 faded">
- <div class="breadcrumbs">
- <a href="{{ baseUrl('/shelves') }}" class="text-button">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
- <span class="sep">»</span>
- <a href="{{ baseUrl('/create-shelf') }}" class="text-button">@icon('add'){{ trans('entities.shelves_create') }}</a>
- </div>
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('add') {{ trans('entities.shelves_create') }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/shelves") }}" method="POST" enctype="multipart/form-data">
- @include('shelves/form', ['shelf' => null, 'books' => $books])
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ '/shelves' => [
+ 'text' => trans('entities.shelves'),
+ 'icon' => 'bookshelf',
+ ],
+ '/create-shelf' => [
+ 'text' => trans('entities.shelves_create'),
+ 'icon' => 'add',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.shelves_create') }}</h1>
+ <form action="{{ baseUrl("/shelves") }}" method="POST" enctype="multipart/form-data">
+ @include('shelves.form', ['shelf' => null, 'books' => $books])
+ </form>
</div>
- </div>
- <p class="margin-top large"><br></p>
+ </div>
@include('components.image-manager', ['imageType' => 'cover'])
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('shelves._breadcrumbs', ['shelf' => $shelf])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ trans('entities.shelves_delete') }}</h3>
- <div class="body">
- <p>{{ trans('entities.shelves_delete_explain', ['name' => $shelf->name]) }}</p>
- <p class="text-neg">{{ trans('entities.shelves_delete_confirmation') }}</p>
-
- <form action="{{ $shelf->getUrl() }}" method="POST">
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $shelf,
+ $shelf->getUrl('/delete') => [
+ 'text' => trans('entities.shelves_delete'),
+ 'icon' => 'delete',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('entities.shelves_delete') }}</h1>
+ <p>{{ trans('entities.shelves_delete_explain', ['name' => $shelf->name]) }}</p>
+
+ <div class="grid half">
+ <p class="text-neg">
+ <strong>{{ trans('entities.shelves_delete_confirmation') }}</strong>
+ </p>
+
+ <form action="{{ $shelf->getUrl() }}" method="POST" class="text-right">
{!! csrf_field() !!}
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="button">{{ trans('common.confirm') }}</button>
</form>
</div>
+
+
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('shelves._breadcrumbs', ['shelf' => $shelf])
- </div>
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('edit') {{ trans('entities.shelves_edit') }}</h3>
- <div class="body">
- <form action="{{ $shelf->getUrl() }}" method="POST">
- <input type="hidden" name="_method" value="PUT">
- @include('shelves/form', ['model' => $shelf])
- </form>
- </div>
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $shelf,
+ $shelf->getUrl('/edit') => [
+ 'text' => trans('entities.shelves_edit'),
+ 'icon' => 'edit',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.shelves_edit') }}</h1>
+ <form action="{{ $shelf->getUrl() }}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('shelves.form', ['model' => $shelf])
+ </form>
</div>
</div>
-@include('components.image-manager', ['imageType' => 'cover'])
+
+ @include('components.image-manager', ['imageType' => 'cover'])
@stop
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<html lang="en">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <title>{{ $book->name }}</title>
-
- <style>
- @if (!app()->environment('testing'))
- {!! file_get_contents(public_path('/dist/export-styles.css')) !!}
- @endif
- .page-break {
- page-break-after: always;
- }
- .chapter-hint {
- color: #888;
- margin-top: 32px;
- }
- .chapter-hint + h1 {
- margin-top: 0;
- }
- ul.contents ul li {
- list-style: circle;
- }
- @media screen {
- .page-break {
- border-top: 1px solid #DDD;
- }
- }
- </style>
- @yield('head')
-</head>
-<body>
-<div class="container">
- <div class="row">
- <div class="col-md-8 col-md-offset-2">
- <div class="page-content">
-
- <h1 style="font-size: 4.8em">{{$book->name}}</h1>
-
- <p>{{ $book->description }}</p>
-
- @if(count($bookChildren) > 0)
- <ul class="contents">
- @foreach($bookChildren as $bookChild)
- <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
- @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
- <ul>
- @foreach($bookChild->pages as $page)
- <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
- @endforeach
- </ul>
- @endif
- @endforeach
- </ul>
- @endif
-
- @foreach($bookChildren as $bookChild)
- <div class="page-break"></div>
- <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
- @if($bookChild->isA('chapter'))
- <p>{{ $bookChild->description }}</p>
- @if(count($bookChild->pages) > 0)
- @foreach($bookChild->pages as $page)
- <div class="page-break"></div>
- <div class="chapter-hint">{{$bookChild->name}}</div>
- <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
- {!! $page->html !!}
- @endforeach
- @endif
- @else
- {!! $bookChild->html !!}
- @endif
- @endforeach
-
- </div>
- </div>
- </div>
-</div>
-</body>
-</html>
-
{{ csrf_field() }}
+
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>
- @include('form/text', ['name' => 'name'])
+ @include('form.text', ['name' => 'name'])
</div>
<div class="form-group description-input">
<label for="description">{{ trans('common.description') }}</label>
- @include('form/textarea', ['name' => 'description'])
+ @include('form.textarea', ['name' => 'description'])
</div>
-<div shelf-sort class="row">
- <div class="col-md-6">
- <div class="form-group">
- <label for="books">{{ trans('entities.shelves_books') }}</label>
- <input type="hidden" id="books-input" name="books"
- value="{{ isset($shelf) ? $shelf->books->implode('id', ',') : '' }}">
- <div class="scroll-box">
- <div class="scroll-box-item text-small text-muted instruction">
- {{ trans('entities.shelves_drag_books') }}
- </div>
- <div class="scroll-box-item scroll-box-placeholder" style="display: none;">
- <a href="#" class="text-muted">@icon('book') ...</a>
- </div>
- @if (isset($shelfBooks) && count($shelfBooks) > 0)
- @foreach ($shelfBooks as $book)
- <div data-id="{{ $book->id }}" class="scroll-box-item">
- <a href="{{ $book->getUrl() }}" class="text-book">@icon('book'){{ $book->name }}</a>
- </div>
- @endforeach
- @endif
+<div shelf-sort class="grid half gap-xl">
+ <div class="form-group">
+ <label for="books">{{ trans('entities.shelves_books') }}</label>
+ <input type="hidden" id="books-input" name="books"
+ value="{{ isset($shelf) ? $shelf->books->implode('id', ',') : '' }}">
+ <div class="scroll-box">
+ <div class="scroll-box-item text-small text-muted instruction">
+ {{ trans('entities.shelves_drag_books') }}
</div>
- </div>
- </div>
- <div class="col-md-6">
- <div class="form-group">
- <label for="books">{{ trans('entities.shelves_add_books') }}</label>
- <div class="scroll-box">
- @foreach ($books as $book)
+ <div class="scroll-box-item scroll-box-placeholder" style="display: none;">
+ <a href="#" class="text-muted">@icon('book') ...</a>
+ </div>
+ @if (isset($shelfBooks) && count($shelfBooks) > 0)
+ @foreach ($shelfBooks as $book)
<div data-id="{{ $book->id }}" class="scroll-box-item">
<a href="{{ $book->getUrl() }}" class="text-book">@icon('book'){{ $book->name }}</a>
</div>
@endforeach
- </div>
+ @endif
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="books">{{ trans('entities.shelves_add_books') }}</label>
+ <div class="scroll-box">
+ @foreach ($books as $book)
+ <div data-id="{{ $book->id }}" class="scroll-box-item">
+ <a href="{{ $book->getUrl() }}" class="text-book">@icon('book'){{ $book->name }}</a>
+ </div>
+ @endforeach
</div>
</div>
</div>
<div class="form-group text-right">
<a href="{{ isset($shelf) ? $shelf->getUrl() : baseUrl('/shelves') }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button pos">{{ trans('entities.shelves_save') }}</button>
+ <button type="submit" class="button primary">{{ trans('entities.shelves_save') }}</button>
</div>
\ No newline at end of file
-<div class="bookshelf-grid-item grid-card" data-entity-type="bookshelf" data-entity-id="{{$bookshelf->id}}">
- <div class="featured-image-container">
- <a href="{{$bookshelf->getUrl()}}" title="{{$bookshelf->name}}">
- <img src="{{$bookshelf->getBookCover()}}" alt="{{$bookshelf->name}}">
- </a>
+<a href="{{$shelf->getUrl()}}" class="bookshelf-grid-item grid-card"
+ data-entity-type="bookshelf" data-entity-id="{{$shelf->id}}">
+ <div class="bg-shelf featured-image-container-wrap">
+ <div class="featured-image-container" @if($shelf->cover) style="background-image: url('{{ $shelf->getBookCover() }}')"@endif>
+ </div>
+ @icon('bookshelf')
</div>
<div class="grid-card-content">
- <h2><a class="break-text" href="{{$bookshelf->getUrl()}}" title="{{$bookshelf->name}}">{{$bookshelf->getShortName(35)}}</a></h2>
- @if(isset($bookshelf->searchSnippet))
- <p >{!! $bookshelf->searchSnippet !!}</p>
+ <h2>{{$shelf->getShortName(35)}}</h2>
+ @if(isset($shelf->searchSnippet))
+ <p class="text-muted">{!! $shelf->searchSnippet !!}</p>
@else
- <p >{{ $bookshelf->getExcerpt(130) }}</p>
+ <p class="text-muted">{{ $shelf->getExcerpt(130) }}</p>
@endif
</div>
<div class="grid-card-footer text-muted text-small">
- <span>@include('partials.entity-meta', ['entity' => $bookshelf])</span>
+ @icon('star')<span title="{{$shelf->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $shelf->created_at->diffForHumans()]) }}</span>
+ <br>
+ @icon('edit')<span title="{{ $shelf->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $shelf->updated_at->diffForHumans()]) }}</span>
</div>
-</div>
\ No newline at end of file
+</a>
\ No newline at end of file
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-xs-6 faded">
- <div class="action-buttons text-left">
- @include('shelves/view-toggle', ['shelvesViewType' => $shelvesViewType])
- </div>
- </div>
- <div class="col-xs-6 faded">
- <div class="action-buttons">
+@section('body')
+ @include('shelves.list', ['shelves' => $shelves, 'view' => $view])
+@stop
+
+@section('right')
+
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
@if($currentUser->can('bookshelf-create-all'))
- <a href="{{ baseUrl("/create-shelf") }}" class="text-pos text-button">@icon('add'){{ trans('entities.shelves_create') }}</a>
+ <a href="{{ baseUrl("/create-shelf") }}" class="icon-list-item">
+ <span>@icon('add')</span>
+ <span>{{ trans('entities.shelves_new_action') }}</span>
+ </a>
@endif
+ @include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
</div>
</div>
+
@stop
-@section('sidebar')
+@section('left')
@if($recents)
- <div id="recents" class="card">
- <h3>@icon('view') {{ trans('entities.recently_viewed') }}</h3>
- @include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
+ <div id="recents" class="mb-xl">
+ <h5>{{ trans('entities.recently_viewed') }}</h5>
+ @include('partials.entity-list', ['entities' => $recents, 'style' => 'compact'])
</div>
@endif
- <div id="popular" class="card">
- <h3>@icon('popular') {{ trans('entities.shelves_popular') }}</h3>
+ <div id="popular" class="mb-xl">
+ <h5>{{ trans('entities.shelves_popular') }}</h5>
@if(count($popular) > 0)
- @include('partials/entity-list', ['entities' => $popular, 'style' => 'compact'])
+ @include('partials.entity-list', ['entities' => $popular, 'style' => 'compact'])
@else
- <div class="body text-muted">{{ trans('entities.shelves_popular_empty') }}</div>
+ <div class="text-muted">{{ trans('entities.shelves_popular_empty') }}</div>
@endif
</div>
- <div id="new" class="card">
- <h3>@icon('star-circle') {{ trans('entities.shelves_new') }}</h3>
+ <div id="new" class="mb-xl">
+ <h5>{{ trans('entities.shelves_new') }}</h5>
@if(count($new) > 0)
- @include('partials/entity-list', ['entities' => $new, 'style' => 'compact'])
+ @include('partials.entity-list', ['entities' => $new, 'style' => 'compact'])
@else
- <div class="body text-muted">{{ trans('entities.shelves_new_empty') }}</div>
+ <div class="text-muted">{{ trans('entities.shelves_new_empty') }}</div>
@endif
</div>
-@stop
-
-@section('body')
- @include('shelves/list', ['shelves' => $shelves, 'shelvesViewType' => $shelvesViewType])
- <p><br></p>
@stop
\ No newline at end of file
-<div class="shelf entity-list-item" data-entity-type="bookshelf" data-entity-id="{{$bookshelf->id}}">
- <h4 class="text-shelf"><a class="text-bookshelf entity-list-item-link" href="{{$bookshelf->getUrl()}}">@icon('bookshelf')<span class="entity-list-item-name break-text">{{$bookshelf->name}}</span></a></h4>
- <div class="entity-item-snippet">
- @if(isset($bookshelf->searchSnippet))
- <p class="text-muted break-text">{!! $bookshelf->searchSnippet !!}</p>
- @else
- <p class="text-muted break-text">{{ $bookshelf->getExcerpt() }}</p>
- @endif
+<a href="{{ $shelf->getUrl() }}" class="shelf entity-list-item" data-entity-type="bookshelf" data-entity-id="{{$shelf->id}}">
+ <div class="entity-list-item-image bg-shelf @if($shelf->image_id) has-image @endif" style="background-image: url('{{ $shelf->getBookCover() }}')">
+ @icon('bookshelf')
</div>
+ <div class="content py-xs">
+ <h4 class="entity-list-item-name break-text">{{ $shelf->name }}</h4>
+ <div class="entity-item-snippet">
+ <p class="text-muted break-text mb-none">{{ $shelf->getExcerpt() }}</p>
+ </div>
+ </div>
+</a>
+<div class="entity-shelf-books grid third gap-y-xs entity-list-item-children">
+ @foreach($shelf->books as $book)
+ <div>
+ <a href="{{ $book->getUrl('?shelf=' . $shelf->id) }}" class="entity-chip text-book">
+ @icon('book')
+ {{ $book->name }}
+ </a>
+ </div>
+ @endforeach
</div>
\ No newline at end of file
-<div class="container{{ $shelvesViewType === 'list' ? ' small' : '' }}">
- <h1>{{ trans('entities.shelves') }}</h1>
+<div class="content-wrap mt-m card">
+
+ <div class="grid half v-center">
+ <h1 class="list-heading">{{ trans('entities.shelves') }}</h1>
+ <div class="text-right">
+ @include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'bookshelves'])
+ </div>
+ </div>
+
@if(count($shelves) > 0)
- @if($shelvesViewType === 'grid')
+ @if($view === 'list')
+ <div class="entity-list">
+ @foreach($shelves as $index => $shelf)
+ @if ($index !== 0)
+ <hr class="my-m">
+ @endif
+ @include('shelves.list-item', ['shelf' => $shelf])
+ @endforeach
+ </div>
+ @else
<div class="grid third">
@foreach($shelves as $key => $shelf)
- @include('shelves/grid-item', ['bookshelf' => $shelf])
+ @include('shelves.grid-item', ['shelf' => $shelf])
@endforeach
</div>
- @else
- @foreach($shelves as $shelf)
- @include('shelves/list-item', ['bookshelf' => $shelf])
- <hr>
- @endforeach
@endif
<div>
{!! $shelves->render() !!}
<a href="{{ baseUrl("/create-shelf") }}" class="button outline">@icon('edit'){{ trans('entities.create_now') }}</a>
@endif
@endif
-</div>
\ No newline at end of file
+
+</div>
--- /dev/null
+@extends('simple-layout')
+
+@section('body')
+
+ <div class="container small">
+
+ <div class="my-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $shelf,
+ $shelf->getUrl('/permissions') => [
+ 'text' => trans('entities.shelves_permissions'),
+ 'icon' => 'lock',
+ ]
+ ]])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.shelves_permissions') }}</h1>
+ @include('form.entity-permissions', ['model' => $shelf])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('entities.shelves_copy_permissions_to_books') }}</h2>
+ <p>{{ trans('entities.shelves_copy_permissions_explain') }}</p>
+ <form action="{{ $shelf->getUrl('/copy-permissions') }}" method="post" class="text-right">
+ {{ csrf_field() }}
+ <button class="button">{{ trans('entities.shelves_copy_permissions') }}</button>
+ </form>
+ </div>
+ </div>
+
+@stop
+++ /dev/null
-@extends('simple-layout')
-
-@section('toolbar')
- <div class="col-sm-12 faded">
- @include('shelves._breadcrumbs', ['shelf' => $shelf])
- </div>
-@stop
-
-@section('body')
-
- <div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('lock') {{ trans('entities.shelves_permissions') }}</h3>
- <div class="body">
- @include('form/restriction-form', ['model' => $shelf])
- </div>
- </div>
-
- <p> </p>
-
- <div class="card">
- <h3>@icon('copy') {{ trans('entities.shelves_copy_permissions_to_books') }}</h3>
- <div class="body">
- <p>{{ trans('entities.shelves_copy_permissions_explain') }}</p>
- <form action="{{ $shelf->getUrl('/copy-permissions') }}" method="post" class="text-right">
- {{ csrf_field() }}
- <button class="button">{{ trans('entities.shelves_copy_permissions') }}</button>
- </form>
- </div>
- </div>
- </div>
-
-@stop
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-sm-6 col-xs-1 faded">
- @include('shelves._breadcrumbs', ['shelf' => $shelf])
+@section('body')
+
+ <div class="mb-s">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $shelf,
+ ]])
</div>
- <div class="col-sm-6 col-xs-11">
- <div class="action-buttons faded">
- @if(userCan('bookshelf-update', $shelf))
- <a href="{{ $shelf->getUrl('/edit') }}" class="text-button text-primary">@icon('edit'){{ trans('common.edit') }}</a>
- @endif
- @if(userCan('restrictions-manage', $shelf) || userCan('bookshelf-delete', $shelf))
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('more'){{ trans('common.more') }}</a>
- <ul>
- @if(userCan('restrictions-manage', $shelf))
- <li><a href="{{ $shelf->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li>
+
+ <div class="card content-wrap">
+ <h1 class="break-text">{{$shelf->name}}</h1>
+ <div class="book-content">
+ <p class="text-muted">{!! nl2br(e($shelf->description)) !!}</p>
+ @if(count($books) > 0)
+ <div class="entity-list">
+ @foreach($books as $book)
+ @include('books.list-item', ['book' => $book])
+ @endforeach
+ </div>
+ @else
+ <div class="mt-xl">
+ <hr>
+ <p class="text-muted italic mt-xl mb-m">{{ trans('entities.shelves_empty_contents') }}</p>
+ <div class="icon-list inline block">
+ @if(userCan('book-create-all') && userCan('bookshelf-update', $shelf))
+ <a href="{{ $shelf->getUrl('/create-book') }}" class="icon-list-item text-book">
+ <span class="icon">@icon('add')</span>
+ <span>{{ trans('entities.books_create') }}</span>
+ </a>
@endif
- @if(userCan('bookshelf-delete', $shelf))
- <li><a href="{{ $shelf->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li>
+ @if(userCan('bookshelf-update', $shelf))
+ <a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item text-bookshelf">
+ <span class="icon">@icon('edit')</span>
+ <span>{{ trans('entities.shelves_edit_and_assign') }}</span>
+ </a>
@endif
- </ul>
+ </div>
</div>
@endif
</div>
</div>
+
@stop
-@section('sidebar')
+@section('left')
@if($shelf->tags->count() > 0)
- <section>
+ <div id="tags" class="mb-xl">
@include('components.tag-list', ['entity' => $shelf])
- </section>
+ </div>
@endif
- <div class="card entity-details">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
- <div class="body text-small text-muted blended-links">
+ <div id="details" class="mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
+ <div class="text-small text-muted blended-links">
@include('partials.entity-meta', ['entity' => $shelf])
@if($shelf->restricted)
<div class="active-restriction">
</div>
@if(count($activity) > 0)
- <div class="activity card">
- <h3>@icon('time') {{ trans('entities.recent_activity') }}</h3>
- @include('partials/activity-list', ['activity' => $activity])
+ <div class="mb-xl">
+ <h5>{{ trans('entities.recent_activity') }}</h5>
+ @include('partials.activity-list', ['activity' => $activity])
</div>
@endif
@stop
-@section('body')
+@section('right')
+ <div class="actions mb-xl">
+ <h5>{{ trans('common.actions') }}</h5>
+ <div class="icon-list text-primary">
- <div class="container small nopad">
- <h1 class="break-text">{{$shelf->name}}</h1>
- <div class="book-content">
- <p class="text-muted">{!! nl2br(e($shelf->description)) !!}</p>
- @if(count($books) > 0)
- <div class="page-list">
- <hr>
- @foreach($books as $book)
- @include('books/list-item', ['book' => $book])
- <hr>
- @endforeach
- </div>
- @else
- <p>
- <hr>
- <span class="text-muted italic">{{ trans('entities.shelves_empty_contents') }}</span>
- @if(userCan('bookshelf-create', $shelf))
- <br>
- <a href="{{ $shelf->getUrl('/edit') }}" class="button outline bookshelf">{{ trans('entities.shelves_edit_and_assign') }}</a>
- @endif
- </p>
+ @if(userCan('book-create-all') && userCan('bookshelf-update', $shelf))
+ <a href="{{ $shelf->getUrl('/create-book') }}" class="icon-list-item">
+ <span class="icon">@icon('add')</span>
+ <span>{{ trans('entities.books_new_action') }}</span>
+ </a>
@endif
- </div>
+ <hr class="primary-background">
+
+ @if(userCan('bookshelf-update', $shelf))
+ <a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item">
+ <span>@icon('edit')</span>
+ <span>{{ trans('common.edit') }}</span>
+ </a>
+ @endif
+
+ @if(userCan('restrictions-manage', $shelf))
+ <a href="{{ $shelf->getUrl('/permissions') }}" class="icon-list-item">
+ <span>@icon('lock')</span>
+ <span>{{ trans('entities.permissions') }}</span>
+ </a>
+ @endif
+ @if(userCan('bookshelf-delete', $shelf))
+ <a href="{{ $shelf->getUrl('/delete') }}" class="icon-list-item">
+ <span>@icon('delete')</span>
+ <span>{{ trans('common.delete') }}</span>
+ </a>
+ @endif
+
+ </div>
+ </div>
@stop
+
+
+
+
+++ /dev/null
-<form action="{{ baseUrl("/settings/users/{$currentUser->id}/switch-shelf-view") }}" method="POST" class="inline">
- {!! csrf_field() !!}
- {!! method_field('PATCH') !!}
- <input type="hidden" value="{{ $shelvesViewType === 'list'? 'grid' : 'list' }}" name="view_type">
- @if ($shelvesViewType === 'list')
- <button type="submit" class="text-pos text-button">@icon('grid'){{ trans('common.grid_view') }}</button>
- @else
- <button type="submit" class="text-pos text-button">@icon('list'){{ trans('common.list_view') }}</button>
- @endif
-</form>
\ No newline at end of file
+++ /dev/null
-@extends('base')
-
-@section('body-class', 'sidebar-layout')
-
-@section('content')
-
- <div class="toolbar-container">
- <div class="faded-small toolbar">
- <div class="container fluid">
- <div class="row">
- @yield('toolbar')
- </div>
- </div>
- </div>
- </div>
-
-
- <div class="flex-fill flex" @yield('container-attrs') >
-
- <div sidebar class="sidebar flex print-hidden" id="sidebar">
- <div class="sidebar-toggle primary-background-light">@icon('caret-right-circle')
- </div>
- <div class="scroll-body">
- @yield('sidebar')
- </div>
- </div>
-
- <div class="content flex @yield('body-wrap-classes')">
- @yield('body')
- </div>
- </div>
-
-
-@stop
@extends('base')
-@section('body-class', 'shaded')
-
@section('content')
- <div class="toolbar-container">
- <div class="faded-small toolbar">
- <div class="container fluid">
- <div class="row">
- @yield('toolbar')
- </div>
- </div>
- </div>
- </div>
-
-
<div class="flex-fill flex">
<div class="content flex">
<div class="scroll-body">
</div>
</div>
-
@stop
--- /dev/null
+@extends('base')
+
+@section('body-class', 'tri-layout')
+
+@section('content')
+
+ <div class="tri-layout-mobile-tabs text-primary" >
+ <div class="grid half no-break no-gap">
+ <div class="tri-layout-mobile-tab px-m py-s" tri-layout-mobile-tab="info">
+ {{ trans('common.tab_info') }}
+ </div>
+ <div class="tri-layout-mobile-tab px-m py-s active" tri-layout-mobile-tab="content">
+ {{ trans('common.tab_content') }}
+ </div>
+ </div>
+ </div>
+
+ <div class="tri-layout-container" tri-layout @yield('container-attrs') >
+
+ <div class="tri-layout-left print-hidden pt-m" id="sidebar">
+ <div class="tri-layout-left-contents">
+ @yield('left')
+ </div>
+ </div>
+
+ <div class="@yield('body-wrap-classes') tri-layout-middle">
+ <div class="tri-layout-middle-contents">
+ @yield('body')
+ </div>
+ </div>
+
+ <div class="tri-layout-right print-hidden pt-m">
+ <div class="tri-layout-right-contents">
+ @yield('right')
+ </div>
+ </div>
+ </div>
+
+@stop
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'users'])
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('users-add') {{ trans('settings.users_add_new') }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/settings/users/create") }}" method="post">
- {!! csrf_field() !!}
- @include('users/forms/' . $authMethod)
- <div class="form-group text-right">
- <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button class="button pos" type="submit">{{ trans('common.save') }}</button>
- </div>
- </form>
- </div>
+
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'users'])
+ </div>
+
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ trans('settings.users_add_new') }}</h1>
+
+ <form action="{{ baseUrl("/settings/users/create") }}" method="post">
+ {!! csrf_field() !!}
+
+ <div class="setting-list">
+ @include('users.form')
+ </div>
+
+ <div class="form-group text-right">
+ <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button class="button primary" type="submit">{{ trans('common.save') }}</button>
+ </div>
+
+ </form>
+
</div>
</div>
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'users'])
-@stop
-
@section('body')
-
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('delete') {{ trans('settings.users_delete') }}</h3>
- <div class="body">
- <p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
- <p class="text-neg">{{ trans('settings.users_delete_confirm') }}</p>
- <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="POST">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="DELETE">
- <a href="{{ baseUrl("/settings/users/{$user->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
- <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
- </form>
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'users'])
+ </div>
+
+ <div class="card content-wrap auto-height">
+ <h1 class="list-heading">{{ trans('settings.users_delete') }}</h1>
+
+ <p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
+
+ <div class="grid half">
+ <p class="text-neg"><strong>{{ trans('settings.users_delete_confirm') }}</strong></p>
+ <div>
+ <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="POST" class="text-right">
+ {!! csrf_field() !!}
+
+ <input type="hidden" name="_method" value="DELETE">
+ <a href="{{ baseUrl("/settings/users/{$user->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ <button type="submit" class="button primary">{{ trans('common.confirm') }}</button>
+ </form>
+ </div>
</div>
+
</div>
</div>
-
@stop
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'users'])
-@stop
-
@section('body')
-
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('edit') {{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
- <div class="row">
- <div class="col-sm-6">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="put">
- @include('users.forms.' . $authMethod, ['model' => $user])
- </div>
- <div class="col-sm-6">
- <div class="form-group" id="logo-control">
- <label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
- <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'users'])
+ </div>
- @include('components.image-picker', [
- 'resizeHeight' => '512',
- 'resizeWidth' => '512',
- 'showRemove' => false,
- 'defaultImage' => baseUrl('/user_avatar.png'),
- 'currentImage' => $user->getAvatar(80),
- 'currentId' => $user->image_id,
- 'name' => 'image_id',
- 'imageClass' => 'avatar large'
- ])
- </div>
- <div class="form-group">
- <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
- <select name="setting[language]" id="user-language">
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h1>
+ <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
- @foreach(trans('settings.language_select') as $lang => $label)
- <option @if(setting()->getUser($user, 'language', config('app.default_locale')) === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
- @endforeach
- </select>
- </div>
+ <div class="setting-list">
+ @include('users.form', ['model' => $user, 'authMethod' => $authMethod])
+
+ <div class="grid half gap-xl">
+ <div>
+ <label for="user-avatar" class="setting-list-label">{{ trans('settings.users_avatar') }}</label>
+ <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
+ </div>
+ <div>
+ @include('components.image-picker', [
+ 'resizeHeight' => '512',
+ 'resizeWidth' => '512',
+ 'showRemove' => false,
+ 'defaultImage' => baseUrl('/user_avatar.png'),
+ 'currentImage' => $user->getAvatar(80),
+ 'currentId' => $user->image_id,
+ 'name' => 'image_id',
+ 'imageClass' => 'avatar large'
+ ])
</div>
</div>
- <div class="form-group text-right">
- <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
- @if($authMethod !== 'system')
- <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="neg button">{{ trans('settings.users_delete') }}</a>
- @endif
- <button class="button pos" type="submit">{{ trans('common.save') }}</button>
+
+ <div class="grid half gap-xl v-center">
+ <div>
+ <label for="user-language" class="setting-list-label">{{ trans('settings.users_preferred_language') }}</label>
+ <p class="small">
+ {{ trans('settings.users_preferred_language_desc') }}
+ </p>
+ </div>
+ <div>
+ <select name="setting[language]" id="user-language">
+ @foreach(trans('settings.language_select') as $lang => $label)
+ <option @if(setting()->getUser($user, 'language', config('app.default_locale')) === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
+ @endforeach
+ </select>
+ </div>
</div>
- </form>
- </div>
+
+ </div>
+
+ <div class="text-right">
+ <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ @if($authMethod !== 'system')
+ <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="button outline">{{ trans('settings.users_delete') }}</a>
+ @endif
+ <button class="button primary" type="submit">{{ trans('common.save') }}</button>
+ </div>
+ </form>
</div>
@if($currentUser->id === $user->id && count($activeSocialDrivers) > 0)
- <div class="card">
- <h3>@icon('login') {{ trans('settings.users_social_accounts') }}</h3>
- <div class="body">
- <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
- <div class="container">
- <div class="row">
- @foreach($activeSocialDrivers as $driver => $enabled)
- <div class="col-sm-4 col-xs-6 text-center">
- <div>@icon('auth/'. $driver, ['style' => 'width: 56px;height: 56px;'])</div>
- <div>
- @if($user->hasSocialAccount($driver))
- <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button neg">{{ trans('settings.users_social_disconnect') }}</a>
- @else
- <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a>
- @endif
- </div>
- <div> </div>
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.users_social_accounts') }}</h2>
+ <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
+ <div class="container">
+ <div class="grid third">
+ @foreach($activeSocialDrivers as $driver => $enabled)
+ <div class="text-center mb-m">
+ <div>@icon('auth/'. $driver, ['style' => 'width: 56px;height: 56px;'])</div>
+ <div>
+ @if($user->hasSocialAccount($driver))
+ <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button small outline">{{ trans('settings.users_social_disconnect') }}</a>
+ @else
+ <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button small outline">{{ trans('settings.users_social_connect') }}</a>
+ @endif
</div>
- @endforeach
- </div>
+ </div>
+ @endforeach
</div>
</div>
</div>
@endif
-
-
</div>
- <p class="margin-top large"><br></p>
@include('components.image-manager', ['imageType' => 'user'])
-@stop
\ No newline at end of file
+@stop
--- /dev/null
+
+@if($authMethod === 'system' && $user->system_name == 'public')
+ <p class="mb-none text-warn">{{ trans('settings.users_system_public') }}</p>
+@endif
+
+<div class="pt-m">
+ <label class="setting-list-label">{{ trans('settings.users_details') }}</label>
+ @if($authMethod === 'standard')
+ <p class="small">{{ trans('settings.users_details_desc') }}</p>
+ @endif
+ @if($authMethod === 'ldap' || $authMethod === 'system')
+ <p class="small">{{ trans('settings.users_details_desc_no_email') }}</p>
+ @endif
+ <div class="grid half mt-m gap-xl">
+ <div>
+ <label for="name">{{ trans('auth.name') }}</label>
+ @include('form.text', ['name' => 'name'])
+ </div>
+ <div>
+ @if($authMethod !== 'ldap' || userCan('users-manage'))
+ <label for="email">{{ trans('auth.email') }}</label>
+ @include('form.text', ['name' => 'email'])
+ @endif
+ </div>
+ </div>
+</div>
+
+@if($authMethod === 'ldap' && userCan('users-manage'))
+ <div class="grid half gap-xl v-center">
+ <div>
+ <label class="setting-list-label">{{ trans('settings.users_external_auth_id') }}</label>
+ <p class="small">{{ trans('settings.users_external_auth_id_desc') }}</p>
+ </div>
+ <div>
+ @include('form.text', ['name' => 'external_auth_id'])
+ </div>
+ </div>
+@endif
+
+@if(userCan('users-manage'))
+ <div>
+ <label for="role" class="setting-list-label">{{ trans('settings.users_role') }}</label>
+ <p class="small">{{ trans('settings.users_role_desc') }}</p>
+ <div class="mt-m">
+ @include('form.role-checkboxes', ['name' => 'roles', 'roles' => $roles])
+ </div>
+ </div>
+@endif
+
+@if($authMethod === 'standard')
+ <div>
+ <label class="setting-list-label">{{ trans('settings.users_password') }}</label>
+ <p class="small">{{ trans('settings.users_password_desc') }}</p>
+ @if(isset($model))
+ <p class="small">
+ {{ trans('settings.users_password_warning') }}
+ </p>
+ @endif
+ <div class="grid half mt-m gap-xl">
+ <div>
+ <label for="password">{{ trans('auth.password') }}</label>
+ @include('form.password', ['name' => 'password'])
+ </div>
+ <div>
+ <label for="password-confirm">{{ trans('auth.password_confirm') }}</label>
+ @include('form.password', ['name' => 'password-confirm'])
+ </div>
+ </div>
+ </div>
+@endif
\ No newline at end of file
+++ /dev/null
-<div class="form-group">
- <label for="name">{{ trans('auth.name') }}</label>
- @include('form.text', ['name' => 'name'])
-</div>
-
-@if(userCan('users-manage'))
-<div class="form-group">
- <label for="email">{{ trans('auth.email') }}</label>
- @include('form.text', ['name' => 'email'])
-</div>
-@endif
-
-@if(userCan('users-manage'))
- <div class="form-group">
- <label for="role">{{ trans('settings.users_role') }}</label>
- @include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
- </div>
-@endif
-
-@if(userCan('users-manage'))
- <div class="form-group">
- <label for="external_auth_id">{{ trans('settings.users_external_auth_id') }}</label>
- @include('form.text', ['name' => 'external_auth_id'])
- </div>
-@endif
\ No newline at end of file
+++ /dev/null
-<div class="form-group">
- <label for="name">{{ 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>
-
-@if(userCan('users-manage'))
- <div class="form-group">
- <label for="role">{{ trans('settings.users_role') }}</label>
- @include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
- </div>
-@endif
-
-@if(isset($model))
- <div class="form-group">
- <span class="text-muted">
- {{ trans('settings.users_password_warning') }}
- </span>
- </div>
-@endif
-
-<div class="form-group">
- <label for="password">{{ trans('auth.password') }}</label>
- @include('form.password', ['name' => 'password'])
-</div>
-
-<div class="form-group">
- <label for="password-confirm">{{ trans('auth.password_confirm') }}</label>
- @include('form.password', ['name' => 'password-confirm'])
-</div>
\ No newline at end of file
+++ /dev/null
-@if($user->system_name == 'public')
- <p>{{ trans('settings.users_system_public') }}</p>
-@endif
-
-<div class="form-group">
- <label for="name">{{ 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>
-
-@if(userCan('users-manage'))
- <div class="form-group">
- <label for="role">{{ trans('settings.users_role') }}</label>
- @include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
- </div>
-@endif
-
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'users'])
-@stop
-
@section('body')
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('users') {{ trans('settings.users') }}</h3>
- <div class="body">
- <div class="container">
- <div class="row">
- <div class="col-sm-4">
- <form method="get" action="{{ baseUrl("/settings/users") }}">
- @foreach(collect($listDetails)->except('search') as $name => $val)
- <input type="hidden" name="{{ $name }}" value="{{ $val }}">
- @endforeach
- <input type="text" name="search" placeholder="{{ trans('settings.users_search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif>
- </form>
- </div>
- <div class="col-sm-8 text-right">
- @if(userCan('users-manage'))
- <a href="{{ baseUrl("/settings/users/create") }}" style="margin-top: 0;" class="pos button">{{ trans('settings.users_add_new') }}</a>
- @endif
- </div>
+
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'users'])
+ </div>
+
+ <div class="card content-wrap">
+
+ <div class="grid right-focus v-center">
+ <h1 class="list-heading">{{ trans('settings.users') }}</h1>
+
+ <div class="text-right">
+ <div class="block inline mr-s">
+ <form method="get" action="{{ baseUrl("/settings/users") }}">
+ @foreach(collect($listDetails)->except('search') as $name => $val)
+ <input type="hidden" name="{{ $name }}" value="{{ $val }}">
+ @endforeach
+ <input type="text" name="search" placeholder="{{ trans('settings.users_search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif>
+ </form>
</div>
+ @if(userCan('users-manage'))
+ <a href="{{ baseUrl("/settings/users/create") }}" style="margin-top: 0;" class="outline button">{{ trans('settings.users_add_new') }}</a>
+ @endif
</div>
+ </div>
- <table class="table">
+ {{--TODO - Add last login--}}
+ <table class="table">
+ <tr>
+ <th></th>
+ <th>
+ <a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'name']) }}">{{ trans('auth.name') }}</a>
+ /
+ <a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'email']) }}">{{ trans('auth.email') }}</a>
+ </th>
+ <th>{{ trans('settings.role_user_roles') }}</th>
+ </tr>
+ @foreach($users as $user)
<tr>
- <th></th>
- <th><a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'name']) }}">{{ trans('auth.name') }}</a></th>
- <th><a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'email']) }}">{{ trans('auth.email') }}</a></th>
- <th>{{ trans('settings.role_user_roles') }}</th>
+ <td class="text-center" style="line-height: 0;"><img class="avatar med" src="{{ $user->getAvatar(40)}}" alt="{{ $user->name }}"></td>
+ <td>
+ @if(userCan('users-manage') || $currentUser->id == $user->id)
+ <a href="{{ baseUrl("/settings/users/{$user->id}") }}">
+ @endif
+ {{ $user->name }} <br> <span class="text-muted">{{ $user->email }}</span>
+ @if(userCan('users-manage') || $currentUser->id == $user->id)
+ </a>
+ @endif
+ </td>
+ <td>
+ @foreach($user->roles as $index => $role)
+ <small><a href="{{ baseUrl("/settings/roles/{$role->id}") }}">{{$role->display_name}}</a>@if($index !== count($user->roles) -1),@endif</small>
+ @endforeach
+ </td>
</tr>
- @foreach($users as $user)
- <tr>
- <td style="line-height: 0;"><img class="avatar med" src="{{ $user->getAvatar(40)}}" alt="{{ $user->name }}"></td>
- <td>
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- <a href="{{ baseUrl("/settings/users/{$user->id}") }}">
- @endif
- {{ $user->name }}
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- </a>
- @endif
- </td>
- <td>
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- <a href="{{ baseUrl("/settings/users/{$user->id}") }}">
- @endif
- {{ $user->email }}
- @if(userCan('users-manage') || $currentUser->id == $user->id)
- </a>
- @endif
- </td>
- <td>
- @foreach($user->roles as $index => $role)
- <small><a href="{{ baseUrl("/settings/roles/{$role->id}") }}">{{$role->display_name}}</a>@if($index !== count($user->roles) -1),@endif</small>
- @endforeach
- </td>
- </tr>
- @endforeach
- </table>
-
- <div>
- {{ $users->links() }}
- </div>
+ @endforeach
+ </table>
+ <div>
+ {{ $users->links() }}
</div>
</div>
-@extends('sidebar-layout')
-
-@section('toolbar')
- <div class="col-sm-6 col-xs-1 faded">
- <div class="breadcrumbs">
- <a href="{{ $user->getProfileUrl() }}" class="text-button">@icon('user'){{ $user->name }}</a>
- </div>
- </div>
-@stop
-
-@section('sidebar')
- <div class="card" id="recent-activity">
- <h3>@icon('time') {{ trans('entities.recent_activity') }}</h3>
- @include('partials/activity-list', ['activity' => $activity])
- </div>
-@stop
+@extends('simple-layout')
@section('body')
- <div class="container small">
+ <div class="container pt-xl">
- <div class="padded-top large"></div>
+ <div class="grid right-focus reverse-collapse">
- <div class="row">
- <div class="col-md-7">
- <div class="clearfix">
- <div class="padded-right float left">
- <img class="avatar square huge" src="{{ $user->getAvatar(120) }}" alt="{{ $user->name }}">
- </div>
- <div>
- <h3 style="margin-top: 0;">{{ $user->name }}</h3>
- <p class="text-muted">
- {{ trans('entities.profile_user_for_x', ['time' => $user->created_at->diffForHumans(null, true)]) }}
- </p>
- </div>
+ <div>
+ <div id="recent-user-activity" class="mb-xl">
+ <h5>{{ trans('entities.recent_activity') }}</h5>
+ @include('partials.activity-list', ['activity' => $activity])
</div>
</div>
- <div class="col-md-5 text-bigger" id="content-counts">
- <div class="text-muted">{{ trans('entities.profile_created_content') }}</div>
- <a href="#recent-books">
- <div class="text-book">
- @icon('book') {{ trans_choice('entities.x_books', $assetCounts['books']) }}
- </div>
- </a>
- <a href="#recent-chapters">
- <div class="text-chapter">
- @icon('chapter') {{ trans_choice('entities.x_chapters', $assetCounts['chapters']) }}
- </div>
- </a>
- <a href="#recent-pages">
- <div class="text-page">
- @icon('page') {{ trans_choice('entities.x_pages', $assetCounts['pages']) }}
+
+ <div>
+ <div class="card content-wrap auto-height">
+ <div class="grid half v-center">
+ <div>
+ <div class="mr-m float left">
+ <img class="avatar square huge" src="{{ $user->getAvatar(120) }}" alt="{{ $user->name }}">
+ </div>
+ <div>
+ <h4 class="mt-md">{{ $user->name }}</h4>
+ <p class="text-muted">
+ {{ trans('entities.profile_user_for_x', ['time' => $user->created_at->diffForHumans(null, true)]) }}
+ </p>
+ </div>
+ </div>
+ <div id="content-counts">
+ <div class="text-muted">{{ trans('entities.profile_created_content') }}</div>
+ <div class="grid half v-center no-row-gap">
+ <div class="icon-list">
+ <a href="#recent-pages" class="text-page icon-list-item">
+ <span>@icon('page')</span>
+ <span>{{ trans_choice('entities.x_pages', $assetCounts['pages']) }}</span>
+ </a>
+ <a href="#recent-chapters" class="text-chapter icon-list-item">
+ <span>@icon('chapter')</span>
+ <span>{{ trans_choice('entities.x_chapters', $assetCounts['chapters']) }}</span>
+ </a>
+ </div>
+ <div class="icon-list">
+ <a href="#recent-books" class="text-book icon-list-item">
+ <span>@icon('book')</span>
+ <span>{{ trans_choice('entities.x_books', $assetCounts['books']) }}</span>
+ </a>
+ <a href="#recent-shelves" class="text-bookshelf icon-list-item">
+ <span>@icon('bookshelf')</span>
+ <span>{{ trans_choice('entities.x_shelves', $assetCounts['shelves']) }}</span>
+ </a>
+ </div>
+ </div>
+
+ </div>
</div>
- </a>
- </div>
- </div>
+ </div>
+
+ <div class="card content-wrap auto-height book-contents">
+ <h2 id="recent-pages" class="list-heading">
+ {{ trans('entities.recently_created_pages') }}
+ @if (count($recentlyCreated['pages']) > 0)
+ <a href="{{ baseUrl('/search?term=' . urlencode('{created_by:'.$user->id.'} {type:page}') ) }}" class="text-small ml-s">{{ trans('common.view_all') }}</a>
+ @endif
+ </h2>
+ @if (count($recentlyCreated['pages']) > 0)
+ @include('partials.entity-list', ['entities' => $recentlyCreated['pages'], 'showPath' => true])
+ @else
+ <p class="text-muted">{{ trans('entities.profile_not_created_pages', ['userName' => $user->name]) }}</p>
+ @endif
+ </div>
+ <div class="card content-wrap auto-height book-contents">
+ <h2 id="recent-chapters" class="list-heading">
+ {{ trans('entities.recently_created_chapters') }}
+ @if (count($recentlyCreated['chapters']) > 0)
+ <a href="{{ baseUrl('/search?term=' . urlencode('{created_by:'.$user->id.'} {type:chapter}') ) }}" class="text-small ml-s">{{ trans('common.view_all') }}</a>
+ @endif
+ </h2>
+ @if (count($recentlyCreated['chapters']) > 0)
+ @include('partials.entity-list', ['entities' => $recentlyCreated['chapters'], 'showPath' => true])
+ @else
+ <p class="text-muted">{{ trans('entities.profile_not_created_chapters', ['userName' => $user->name]) }}</p>
+ @endif
+ </div>
- <hr class="even">
- <h3 id="recent-pages">{{ trans('entities.recently_created_pages') }}</h3>
- @if (count($recentlyCreated['pages']) > 0)
- @include('partials/entity-list', ['entities' => $recentlyCreated['pages']])
- @else
- <p class="text-muted">{{ trans('entities.profile_not_created_pages', ['userName' => $user->name]) }}</p>
- @endif
+ <div class="card content-wrap auto-height book-contents">
+ <h2 id="recent-books" class="list-heading">
+ {{ trans('entities.recently_created_books') }}
+ @if (count($recentlyCreated['books']) > 0)
+ <a href="{{ baseUrl('/search?term=' . urlencode('{created_by:'.$user->id.'} {type:book}') ) }}" class="text-small ml-s">{{ trans('common.view_all') }}</a>
+ @endif
+ </h2>
+ @if (count($recentlyCreated['books']) > 0)
+ @include('partials.entity-list', ['entities' => $recentlyCreated['books'], 'showPath' => true])
+ @else
+ <p class="text-muted">{{ trans('entities.profile_not_created_books', ['userName' => $user->name]) }}</p>
+ @endif
+ </div>
+
+ <div class="card content-wrap auto-height book-contents">
+ <h2 id="recent-shelves" class="list-heading">
+ {{ trans('entities.recently_created_shelves') }}
+ @if (count($recentlyCreated['shelves']) > 0)
+ <a href="{{ baseUrl('/search?term=' . urlencode('{created_by:'.$user->id.'} {type:bookshelf}') ) }}" class="text-small ml-s">{{ trans('common.view_all') }}</a>
+ @endif
+ </h2>
+ @if (count($recentlyCreated['shelves']) > 0)
+ @include('partials.entity-list', ['entities' => $recentlyCreated['shelves'], 'showPath' => true])
+ @else
+ <p class="text-muted">{{ trans('entities.profile_not_created_shelves', ['userName' => $user->name]) }}</p>
+ @endif
+ </div>
+ </div>
+
+ </div>
- <hr class="even">
- <h3 id="recent-chapters">{{ trans('entities.recently_created_chapters') }}</h3>
- @if (count($recentlyCreated['chapters']) > 0)
- @include('partials/entity-list', ['entities' => $recentlyCreated['chapters']])
- @else
- <p class="text-muted">{{ trans('entities.profile_not_created_chapters', ['userName' => $user->name]) }}</p>
- @endif
- <hr class="even">
- <h3 id="recent-books">{{ trans('entities.recently_created_books') }}</h3>
- @if (count($recentlyCreated['books']) > 0)
- @include('partials/entity-list', ['entities' => $recentlyCreated['books']])
- @else
- <p class="text-muted">{{ trans('entities.profile_not_created_books', ['userName' => $user->name]) }}</p>
- @endif
</div>
->where('path', '.*$');
Route::group(['prefix' => 'pages'], function() {
- Route::get('/recently-created', 'PageController@showRecentlyCreated');
Route::get('/recently-updated', 'PageController@showRecentlyUpdated');
});
Route::get('/{slug}', 'BookshelfController@show');
Route::put('/{slug}', 'BookshelfController@update');
Route::delete('/{slug}', 'BookshelfController@destroy');
- Route::get('/{slug}/permissions', 'BookshelfController@showRestrict');
- Route::put('/{slug}/permissions', 'BookshelfController@restrict');
+ Route::get('/{slug}/permissions', 'BookshelfController@showPermissions');
+ Route::put('/{slug}/permissions', 'BookshelfController@permissions');
Route::post('/{slug}/copy-permissions', 'BookshelfController@copyPermissions');
+
+ Route::get('/{shelfSlug}/create-book', 'BookController@create');
+ Route::post('/{shelfSlug}/create-book', 'BookController@store');
});
Route::get('/create-book', 'BookController@create');
Route::delete('/{id}', 'BookController@destroy');
Route::get('/{slug}/sort-item', 'BookController@getSortItem');
Route::get('/{slug}', 'BookController@show');
- Route::get('/{bookSlug}/permissions', 'BookController@showRestrict');
- Route::put('/{bookSlug}/permissions', 'BookController@restrict');
+ Route::get('/{bookSlug}/permissions', 'BookController@showPermissions');
+ Route::put('/{bookSlug}/permissions', 'BookController@permissions');
Route::get('/{slug}/delete', 'BookController@showDelete');
Route::get('/{bookSlug}/sort', 'BookController@sort');
Route::put('/{bookSlug}/sort', 'BookController@saveSort');
Route::post('/{bookSlug}/page/{pageSlug}/copy', 'PageController@copy');
Route::get('/{bookSlug}/page/{pageSlug}/delete', 'PageController@showDelete');
Route::get('/{bookSlug}/draft/{pageId}/delete', 'PageController@showDeleteDraft');
- Route::get('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@showRestrict');
- Route::put('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@restrict');
+ Route::get('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@showPermissions');
+ Route::put('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@permissions');
Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
Route::delete('/{bookSlug}/page/{pageSlug}', 'PageController@destroy');
Route::delete('/{bookSlug}/draft/{pageId}', 'PageController@destroyDraft');
Route::get('/{bookSlug}/page/{pageSlug}/revisions', 'PageController@showRevisions');
Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}', 'PageController@showRevision');
Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}/changes', 'PageController@showRevisionChanges');
- Route::get('/{bookSlug}/page/{pageSlug}/revisions/{revId}/restore', 'PageController@restoreRevision');
+ Route::put('/{bookSlug}/page/{pageSlug}/revisions/{revId}/restore', 'PageController@restoreRevision');
Route::delete('/{bookSlug}/page/{pageSlug}/revisions/{revId}/delete', 'PageController@destroyRevision');
// Chapters
Route::get('/{bookSlug}/chapter/{chapterSlug}/move', 'ChapterController@showMove');
Route::put('/{bookSlug}/chapter/{chapterSlug}/move', 'ChapterController@move');
Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit');
- Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showRestrict');
+ Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showPermissions');
Route::get('/{bookSlug}/chapter/{chapterSlug}/export/pdf', 'ChapterController@exportPdf');
Route::get('/{bookSlug}/chapter/{chapterSlug}/export/html', 'ChapterController@exportHtml');
Route::get('/{bookSlug}/chapter/{chapterSlug}/export/plaintext', 'ChapterController@exportPlainText');
- Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@restrict');
+ Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@permissions');
Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
});
Route::get('/search', 'SearchController@search');
Route::get('/search/book/{bookId}', 'SearchController@searchBook');
Route::get('/search/chapter/{bookId}', 'SearchController@searchChapter');
+ Route::get('/search/entity/siblings', 'SearchController@searchSiblings');
// Other Pages
Route::get('/', 'HomeController@index');
Route::get('/users/{id}/delete', 'UserController@delete');
Route::patch('/users/{id}/switch-book-view', 'UserController@switchBookView');
Route::patch('/users/{id}/switch-shelf-view', 'UserController@switchShelfView');
+ Route::patch('/users/{id}/change-sort/{type}', 'UserController@changeSort');
+ Route::patch('/users/{id}/update-expansion-preference/{key}', 'UserController@updateExpansionPreference');
Route::post('/users/create', 'UserController@store');
Route::get('/users/{id}', 'UserController@edit');
Route::put('/users/{id}', 'UserController@update');
->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name, 'name' => $this->mockUser->name]);
}
+ protected function checkLdapReceivesCorrectDetails($serverString, $expectedHost, $expectedPort)
+ {
+ app('config')->set([
+ 'services.ldap.server' => $serverString
+ ]);
+
+ // Standard mocks
+ $this->mockLdap->shouldReceive('setVersion')->once();
+ $this->mockLdap->shouldReceive('setOption')->times(2);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)->andReturn(['count' => 1, 0 => [
+ 'uid' => [$this->mockUser->name],
+ 'cn' => [$this->mockUser->name],
+ 'dn' => ['dc=test' . config('services.ldap.base_dn')]
+ ]]);
+ $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true);
+ $this->mockEscapes(2);
+
+ $this->mockLdap->shouldReceive('connect')->once()
+ ->with($expectedHost, $expectedPort)->andReturn($this->resourceId);
+ $this->mockUserLogin();
+ }
+
+ public function test_ldap_port_provided_on_host_if_host_is_full_uri()
+ {
+ $hostName = 'ldaps://bookstack:8080';
+ $this->checkLdapReceivesCorrectDetails($hostName, $hostName, 389);
+ }
+
+ public function test_ldap_port_parsed_from_server_if_host_is_not_full_uri()
+ {
+ $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com:8080', 'ldap.bookstack.com', 8080);
+ }
+
+ public function test_default_ldap_port_used_if_not_in_server_string_and_not_uri()
+ {
+ $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com', 'ldap.bookstack.com', 389);
+ }
}
public function test_shelves_page_contains_create_link()
{
$resp = $this->asEditor()->get('/shelves');
- $resp->assertElementContains('a', 'Create New Shelf');
+ $resp->assertElementContains('a', 'New Shelf');
}
public function test_shelves_create()
{
$shelf = Bookshelf::first();
$resp = $this->asAdmin()->get($shelf->getUrl());
+ $resp->assertSee($shelf->getUrl('/create-book'));
$resp->assertSee($shelf->getUrl('/edit'));
$resp->assertSee($shelf->getUrl('/permissions'));
$resp->assertSee($shelf->getUrl('/delete'));
+ $resp->assertElementContains('a', 'New Book');
$resp->assertElementContains('a', 'Edit');
$resp->assertElementContains('a', 'Permissions');
$resp->assertElementContains('a', 'Delete');
$this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
}
+ public function test_shelf_create_new_book()
+ {
+ $shelf = Bookshelf::first();
+ $resp = $this->asEditor()->get($shelf->getUrl('/create-book'));
+
+ $resp->assertSee('Create New Book');
+ $resp->assertSee($shelf->getShortName());
+
+ $testName = 'Test Book in Shelf Name';
+
+ $createBookResp = $this->asEditor()->post($shelf->getUrl('/create-book'), [
+ 'name' => $testName,
+ 'description' => 'Book in shelf description'
+ ]);
+ $createBookResp->assertRedirect();
+
+ $newBook = Book::query()->orderBy('id', 'desc')->first();
+ $this->assertDatabaseHas('bookshelves_books', [
+ 'bookshelf_id' => $shelf->id,
+ 'book_id' => $newBook->id,
+ ]);
+
+ $resp = $this->asEditor()->get($shelf->getUrl());
+ $resp->assertSee($testName);
+ }
+
public function test_shelf_delete()
{
$shelf = Bookshelf::first();
$this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]);
}
+ public function test_bookshelves_show_in_breadcrumbs_if_in_context()
+ {
+ $shelf = Bookshelf::first();
+ $shelfBook = $shelf->books()->first();
+ $shelfPage = $shelfBook->pages()->first();
+ $this->asAdmin();
+
+ $bookVisit = $this->get($shelfBook->getUrl());
+ $bookVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
+ $bookVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
+
+ $this->get($shelf->getUrl());
+ $bookVisit = $this->get($shelfBook->getUrl());
+ $bookVisit->assertElementContains('.breadcrumbs', 'Shelves');
+ $bookVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
+
+ $pageVisit = $this->get($shelfPage->getUrl());
+ $pageVisit->assertElementContains('.breadcrumbs', 'Shelves');
+ $pageVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
+
+ $this->get('/books');
+ $pageVisit = $this->get($shelfPage->getUrl());
+ $pageVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
+ $pageVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
+ }
+
}
$pageSearch = $this->get('/ajax/search/entities?term=' . urlencode($page->name));
$pageSearch->assertSee($page->name);
- $pageSearch->assertSee($chapter->getShortName());
- $pageSearch->assertSee($page->book->getShortName());
+ $pageSearch->assertSee($chapter->getShortName(42));
+ $pageSearch->assertSee($page->book->getShortName(42));
$chapterSearch = $this->get('/ajax/search/entities?term=' . urlencode($chapter->name));
$chapterSearch->assertSee($chapter->name);
- $chapterSearch->assertSee($chapter->book->getShortName());
+ $chapterSearch->assertSee($chapter->book->getShortName(42));
}
}
->click('Sort')
->seePageIs($bookToSort->getUrl() . '/sort')
->seeStatusCode(200)
- ->see($bookToSort->name)
- // Ensure page shows other books
- ->see($books[1]->name);
+ ->see($bookToSort->name);
}
public function test_book_sort_item_returns_book_content()
->click('Revisions')->seeStatusCode(200);
}
- public function test_recently_created_pages_view()
- {
- $user = $this->getEditor();
- $content = $this->createEntityChainBelongingToUser($user);
-
- $this->asAdmin()->visit('/pages/recently-created')
- ->seeInNthElement('.entity-list .page', 0, $content['page']->name);
- }
-
public function test_recently_updated_pages_view()
{
$user = $this->getEditor();
$pageResp->assertSee($content);
}
- public function test_page_revision_views_viewable()
- {
- $this->asEditor();
-
- $pageRepo = app(PageRepo::class);
- $page = Page::first();
- $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
- $pageRevision = $page->revisions->last();
-
- $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
- $revisionView->assertStatus(200);
- $revisionView->assertSee('new content');
-
- $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id . '/changes');
- $revisionView->assertStatus(200);
- $revisionView->assertSee('new content');
- }
-
- public function test_page_revision_restore_updates_content()
- {
- $this->asEditor();
-
- $pageRepo = app(PageRepo::class);
- $page = Page::first();
- $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>', 'summary' => 'initial page revision testing']);
- $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page again', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
- $page = Page::find($page->id);
-
-
- $pageView = $this->get($page->getUrl());
- $pageView->assertDontSee('abc123');
- $pageView->assertDontSee('def456');
-
- $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
- $restoreReq = $this->get($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
- $page = Page::find($page->id);
-
- $restoreReq->assertStatus(302);
- $restoreReq->assertRedirect($page->getUrl());
-
- $pageView = $this->get($page->getUrl());
- $pageView->assertSee('abc123');
- $pageView->assertSee('def456');
- }
-
public function test_page_content_scripts_escaped_by_default()
{
$this->asEditor();
$pageView->assertDontSee(htmlentities($script));
}
+ public function test_duplicate_ids_does_not_break_page_render()
+ {
+ $this->asEditor();
+ $pageA = Page::first();
+ $pageB = Page::query()->where('id', '!=', $pageA->id)->first();
+
+ $content = '<ul id="bkmrk-xxx-%28"></ul> <ul id="bkmrk-xxx-%28"></ul>';
+ $pageA->html = $content;
+ $pageA->save();
+
+ $pageB->html = '<ul id="bkmrk-xxx-%28"></ul> <p>{{@'. $pageA->id .'#test}}</p>';
+ $pageB->save();
+
+ $pageView = $this->get($pageB->getUrl());
+ $pageView->assertSuccessful();
+ }
+
+ public function test_duplicate_ids_fixed_on_page_save()
+ {
+ $this->asEditor();
+ $page = Page::first();
+
+ $content = '<p id="bkmrk-test">test a</p>'."\n".'<p id="bkmrk-test">test b</p>';
+ $pageSave = $this->put($page->getUrl(), [
+ 'name' => $page->name,
+ 'html' => $content,
+ 'summary' => ''
+ ]);
+ $pageSave->assertRedirect();
+
+ $updatedPage = Page::where('id', '=', $page->id)->first();
+ $this->assertEquals(substr_count($updatedPage->html, "bkmrk-test\""), 1);
+ }
}
->visit($book->getUrl() . '/create-page')
->visit($chapter->getUrl() . '/create-page')
->visit($book->getUrl())
- ->seeInElement('.page-list', 'New Page');
+ ->seeInElement('.book-contents', 'New Page');
$this->asAdmin()
->visit($book->getUrl())
- ->dontSeeInElement('.page-list', 'New Page')
+ ->dontSeeInElement('.book-contents', 'New Page')
->visit($chapter->getUrl())
- ->dontSeeInElement('.page-list', 'New Page');
+ ->dontSeeInElement('.book-contents', 'New Page');
}
}
<?php namespace Entity;
-
use BookStack\Entities\Page;
+use BookStack\Entities\Repos\PageRepo;
use Tests\TestCase;
class PageRevisionTest extends TestCase
{
+ public function test_page_revision_views_viewable()
+ {
+ $this->asEditor();
+
+ $pageRepo = app(PageRepo::class);
+ $page = Page::first();
+ $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
+ $pageRevision = $page->revisions->last();
+
+ $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
+ $revisionView->assertStatus(200);
+ $revisionView->assertSee('new content');
+
+ $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id . '/changes');
+ $revisionView->assertStatus(200);
+ $revisionView->assertSee('new content');
+ }
+
+ public function test_page_revision_restore_updates_content()
+ {
+ $this->asEditor();
+
+ $pageRepo = app(PageRepo::class);
+ $page = Page::first();
+ $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>', 'summary' => 'initial page revision testing']);
+ $pageRepo->updatePage($page, $page->book_id, ['name' => 'updated page again', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
+ $page = Page::find($page->id);
+
+
+ $pageView = $this->get($page->getUrl());
+ $pageView->assertDontSee('abc123');
+ $pageView->assertDontSee('def456');
+
+ $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
+ $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
+ $page = Page::find($page->id);
+
+ $restoreReq->assertStatus(302);
+ $restoreReq->assertRedirect($page->getUrl());
+
+ $pageView = $this->get($page->getUrl());
+ $pageView->assertSee('abc123');
+ $pageView->assertSee('def456');
+ }
public function test_page_revision_count_increments_on_update()
{
$this->asEditor();
$homeVisit = $this->get('/');
$homeVisit->assertSee('Books');
- $homeVisit->assertSee('book-grid-item grid-card');
+ $homeVisit->assertSee('grid-card');
$homeVisit->assertSee('grid-card-content');
$homeVisit->assertSee('grid-card-footer');
$homeVisit->assertSee('featured-image-container');
$bookUrl = $book->getUrl();
$this->actingAs($this->viewer)
->visit($bookUrl)
- ->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ ->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->actingAs($this->user)
->visit($bookUrl)
- ->seeInElement('.action-buttons', 'New Page')
- ->seeInElement('.action-buttons', 'New Chapter');
+ ->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'delete', 'update']);
->see('You do not have permission')->seePageIs('/');
$this->forceVisit($bookUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'create']);
->type('test content', 'html')
->press('Save Page')
->seePageIs($bookUrl . '/page/test-page');
- $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
- ->seeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
}
public function test_book_update_restriction()
$chapterUrl = $chapter->getUrl();
$this->actingAs($this->user)
->visit($chapterUrl)
- ->seeInElement('.action-buttons', 'New Page');
+ ->seeInElement('.actions', 'New Page');
$this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
$this->forceVisit($chapterUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($chapterUrl)->dontSeeInElement('.action-buttons', 'New Page');
+ $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
$this->setEntityRestrictions($chapter, ['view', 'create']);
->press('Save Page')
->seePageIs($chapter->book->getUrl() . '/page/test-page');
- $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
+ $this->visit($chapterUrl)->seeInElement('.actions', 'New Page');
}
public function test_chapter_update_restriction()
$bookUrl = $book->getUrl();
$this->actingAs($this->viewer)
->visit($bookUrl)
- ->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ ->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'delete', 'update']);
->see('You do not have permission')->seePageIs('/');
$this->forceVisit($bookUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'create']);
->type('test content', 'html')
->press('Save Page')
->seePageIs($bookUrl . '/page/test-page');
- $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
- ->seeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
}
public function test_book_update_restriction_override()
{
$firstBook = Book::first();
$secondBook = Book::find(2);
- $thirdBook = Book::find(3);
$this->setEntityRestrictions($firstBook, ['view', 'update']);
$this->setEntityRestrictions($secondBook, ['view']);
- $this->setEntityRestrictions($thirdBook, ['view', 'update']);
// Test sort page visibility
$this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
->seePageIs('/');
// Check sort page on first book
- $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort')
- ->see($thirdBook->name)
- ->dontSee($secondBook->name);
+ $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort');
}
public function test_book_sort_permission() {
$this->checkAccessPermission('bookshelf-create-all', [
'/create-shelf'
], [
- '/shelves' => 'Create New Shelf'
+ '/shelves' => 'New Shelf'
]);
$this->visit('/create-shelf')
{
$user = \BookStack\Auth\User::first();
$this->asAdmin()->visit('/settings/users/' . $user->id)
- ->seeElement('#roles-admin')
- ->seeElement('#roles-public');
+ ->seeElement('[name="roles[admin]"]')
+ ->seeElement('[name="roles[public]"]');
}
public function test_public_role_visible_in_role_listing()
return $this->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
}
- /**
- * Get the expected upload path for a file.
- * @param $fileName
- * @return string
- */
- protected function getUploadPath($fileName)
- {
- return 'uploads/files/' . Date('Y-m-M') . '/' . $fileName;
- }
-
/**
* Delete all uploaded files.
* To assist with cleanup.
'order' => 1,
'created_by' => $admin->id,
'updated_by' => $admin->id,
- 'path' => $this->getUploadPath($fileName)
];
$upload = $this->uploadFile($fileName, $page->id);
$upload->assertStatus(200);
+
+ $attachment = Attachment::query()->orderBy('id', 'desc')->first();
+ $expectedResp['path'] = $attachment->path;
+
$upload->assertJson($expectedResp);
$this->assertDatabaseHas('attachments', $expectedResp);
$this->deleteUploads();
}
+ public function test_file_upload_does_not_use_filename()
+ {
+ $page = Page::first();
+ $fileName = 'upload_test_file.txt';
+
+
+ $upload = $this->asAdmin()->uploadFile($fileName, $page->id);
+ $upload->assertStatus(200);
+
+ $attachment = Attachment::query()->orderBy('id', 'desc')->first();
+ $this->assertNotContains($fileName, $attachment->path);
+ $this->assertStringEndsWith('.txt', $attachment->path);
+ }
+
public function test_file_display_and_access()
{
$page = Page::first();
$fileName = 'deletion_test.txt';
$this->uploadFile($fileName, $page->id);
- $filePath = base_path('storage/' . $this->getUploadPath($fileName));
+ $attachment = Attachment::query()->orderBy('id', 'desc')->first();
+ $filePath = storage_path($attachment->path);
$this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
$attachment = \BookStack\Uploads\Attachment::first();
$fileName = 'deletion_test.txt';
$this->uploadFile($fileName, $page->id);
- $filePath = base_path('storage/' . $this->getUploadPath($fileName));
+ $attachment = Attachment::query()->orderBy('id', 'desc')->first();
+ $filePath = storage_path($attachment->path);
$this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
$this->assertDatabaseHas('attachments', [
$upload->assertStatus(302);
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped');
+ }
- $this->assertDatabaseMissing('images', [
- 'type' => 'gallery',
- 'name' => $fileName
- ]);
+ public function test_files_with_double_extensions_cannot_be_uploaded()
+ {
+ $page = Page::first();
+ $admin = $this->getAdmin();
+ $this->actingAs($admin);
+
+ $fileName = 'bad.phtml.png';
+ $relPath = $this->getTestImagePath('gallery', $fileName);
+ $this->deleteImage($relPath);
+
+ $file = $this->getTestImage($fileName);
+ $upload = $this->withHeader('Content-Type', 'image/png')->call('POST', '/images/gallery/upload', ['uploaded_to' => $page->id], [], ['file' => $file], []);
+ $upload->assertStatus(302);
+
+ $this->assertFalse(file_exists(public_path($relPath)), 'Uploaded double extension file was uploaded but should have been stopped');
}
public function test_secure_images_uploads_to_correct_place()
--- /dev/null
+<?php namespace Tests;
+
+class UserPreferencesTest extends TestCase
+{
+
+ public function test_update_sort_preference()
+ {
+ $editor = $this->getEditor();
+ $this->actingAs($editor);
+
+ $updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/books', [
+ 'sort' => 'created_at',
+ 'order' => 'desc'
+ ]);
+ $updateRequest->assertStatus(302);
+
+ $this->assertDatabaseHas('settings', [
+ 'setting_key' => 'user:' . $editor->id . ':books_sort',
+ 'value' => 'created_at'
+ ]);
+ $this->assertDatabaseHas('settings', [
+ 'setting_key' => 'user:' . $editor->id . ':books_sort_order',
+ 'value' => 'desc'
+ ]);
+ $this->assertEquals('created_at', setting()->getForCurrentUser('books_sort'));
+ $this->assertEquals('desc', setting()->getForCurrentUser('books_sort_order'));
+ }
+
+ public function test_update_sort_preference_defaults()
+ {
+ $editor = $this->getEditor();
+ $this->actingAs($editor);
+
+ $updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/bookshelves', [
+ 'sort' => 'cat',
+ 'order' => 'dog'
+ ]);
+ $updateRequest->assertStatus(302);
+
+ $this->assertEquals('name', setting()->getForCurrentUser('bookshelves_sort'));
+ $this->assertEquals('asc', setting()->getForCurrentUser('bookshelves_sort_order'));
+ }
+
+ public function test_update_sort_bad_entity_type_handled()
+ {
+ $editor = $this->getEditor();
+ $this->actingAs($editor);
+
+ $updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/dogs', [
+ 'sort' => 'name',
+ 'order' => 'asc'
+ ]);
+ $updateRequest->assertStatus(500);
+
+ $this->assertNotEmpty('name', setting()->getForCurrentUser('bookshelves_sort'));
+ $this->assertNotEmpty('asc', setting()->getForCurrentUser('bookshelves_sort_order'));
+ }
+
+ public function test_update_expansion_preference()
+ {
+ $editor = $this->getEditor();
+ $this->actingAs($editor);
+
+ $updateRequest = $this->patch('/settings/users/' . $editor->id.'/update-expansion-preference/home-details', ['expand' => 'true']);
+ $updateRequest->assertStatus(204);
+
+ $this->assertDatabaseHas('settings', [
+ 'setting_key' => 'user:' . $editor->id . ':section_expansion#home-details',
+ 'value' => 'true'
+ ]);
+ $this->assertEquals(true, setting()->getForCurrentUser('section_expansion#home-details'));
+
+ $invalidKeyRequest = $this->patch('/settings/users/' . $editor->id.'/update-expansion-preference/my-home-details', ['expand' => 'true']);
+ $invalidKeyRequest->assertStatus(500);
+ }
+}
\ No newline at end of file
\Activity::add($entities['page'], 'page_create', $entities['book']->id);
$this->asAdmin()->visit('/user/' . $newUser->id)
- ->seeInElement('#recent-activity', 'updated book')
- ->seeInElement('#recent-activity', 'created page')
- ->seeInElement('#recent-activity', $entities['page']->name);
+ ->seeInElement('#recent-user-activity', 'updated book')
+ ->seeInElement('#recent-user-activity', 'created page')
+ ->seeInElement('#recent-user-activity', $entities['page']->name);
}
public function test_clicking_user_name_in_activity_leads_to_profile_page()
$this->actingAs($editor)
->visit('/books')
->pageNotHasElement('.featured-image-container')
- ->pageHasElement('.content .entity-list-item');
+ ->pageHasElement('.content-wrap .entity-list-item');
}
public function test_books_view_is_grid()
const dev = process.env.NODE_ENV !== 'production';
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
-const ExtractTextPlugin = require("extract-text-webpack-plugin");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = {
target: 'web',
},
{
test: /\.scss$/,
- use: ExtractTextPlugin.extract({
- fallback: "style-loader",
- use: [{
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {}
+ },
+ {
loader: "css-loader", options: {
- sourceMap: dev
- }
+ sourceMap: dev
+ }
}, {
loader: 'postcss-loader',
options: {
loader: "sass-loader", options: {
sourceMap: dev
}
- }]
- })
+ }
+ ]
}
]
},
plugins: [
- new ExtractTextPlugin("[name].css"),
+ new MiniCssExtractPlugin({
+ filename: "[name].css",
+ }),
]
};