mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-08-07 06:25:21 +02:00
Added navigation on page
This commit is contained in:
parent
8c0211d7bc
commit
587062d4d1
9 changed files with 231 additions and 7 deletions
|
@ -1,4 +1,5 @@
|
|||
import database from '../utils/database/index';
|
||||
import Pages from '../controllers/pages';
|
||||
|
||||
const db = database['pagesOrder'];
|
||||
|
||||
|
@ -86,6 +87,105 @@ class PageOrder {
|
|||
return new PageOrder(docs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns previous page for navigation
|
||||
*
|
||||
* @param {string} pageId - page's id
|
||||
* @returns {Promise<string | null>} - previous page id
|
||||
*/
|
||||
public static async getPreviousNavigationPage(pageId: string): Promise<string | null> {
|
||||
const page = await Pages.get(pageId);
|
||||
|
||||
const pageParent = await page.getParent();
|
||||
|
||||
let previousPageId = null;
|
||||
|
||||
// Check if page has a parent
|
||||
if (pageParent._id) {
|
||||
// Get order by parent
|
||||
const order = await this.get(pageParent._id);
|
||||
|
||||
// Get previous page
|
||||
previousPageId = order.getSubPageBefore(pageId);
|
||||
|
||||
// Check if previous page consists in parent order
|
||||
if (!previousPageId) {
|
||||
previousPageId = pageParent._id;
|
||||
}
|
||||
|
||||
return previousPageId;
|
||||
}
|
||||
|
||||
// Get order, which includes getting page, because it has no parent
|
||||
const order = await this.getRootPageOrder();
|
||||
|
||||
// Get parent page before page, which was gotten
|
||||
const parentPageBefore = order.getSubPageBefore(pageId);
|
||||
|
||||
if (parentPageBefore) {
|
||||
// Get previous parent page order
|
||||
const newOrder = await this.get(parentPageBefore);
|
||||
|
||||
// Check if order is empty
|
||||
if (!newOrder._order || newOrder._order.length == 0) {
|
||||
return parentPageBefore;
|
||||
}
|
||||
previousPageId = newOrder._order[newOrder._order.length - 1];
|
||||
}
|
||||
|
||||
return previousPageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next page for navigation
|
||||
*
|
||||
* @param {string} pageId - page's id
|
||||
* @returns {Promise<string | null>} - next page id
|
||||
*/
|
||||
public static async getNextNavigationPage(pageId: string): Promise<string | null> {
|
||||
const page = await Pages.get(pageId);
|
||||
const pageParent = await page.getParent();
|
||||
|
||||
let nextPageId;
|
||||
|
||||
// Check if page has a parent
|
||||
if (pageParent._id) {
|
||||
let order = await this.get(pageParent._id);
|
||||
|
||||
// Get next page by parent order
|
||||
nextPageId = order.getSubPageAfter(pageId);
|
||||
|
||||
// Check if next page consists in parent order
|
||||
if (nextPageId) {
|
||||
return nextPageId;
|
||||
}
|
||||
|
||||
// Get order, which includes parent
|
||||
order = await this.getRootPageOrder();
|
||||
|
||||
nextPageId = order.getSubPageAfter(pageParent._id);
|
||||
|
||||
return nextPageId;
|
||||
}
|
||||
|
||||
// Get order by page id
|
||||
const childOrder = await this.get(pageId);
|
||||
|
||||
// Check if order is empty
|
||||
if (childOrder._order && childOrder._order.length > 0) {
|
||||
nextPageId = childOrder._order[0];
|
||||
|
||||
return nextPageId;
|
||||
}
|
||||
|
||||
// Get order, which includes getting page, because it has no parent
|
||||
const order = await this.getRootPageOrder();
|
||||
|
||||
nextPageId = order.getSubPageAfter(pageId);
|
||||
|
||||
return nextPageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only child page's order
|
||||
*
|
||||
|
@ -182,7 +282,7 @@ class PageOrder {
|
|||
*
|
||||
* @param {string} pageId - identity of page
|
||||
*/
|
||||
public getPageBefore(pageId: string): string | null {
|
||||
public getSubPageBefore(pageId: string): string | null {
|
||||
if (this.order === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
@ -204,7 +304,7 @@ class PageOrder {
|
|||
*
|
||||
* @param pageId - identity of page
|
||||
*/
|
||||
public getPageAfter(pageId: string): string | null {
|
||||
public getSubPageAfter(pageId: string): string | null {
|
||||
if (this.order === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import Aliases from '../controllers/aliases';
|
|||
import Pages from '../controllers/pages';
|
||||
import Alias from '../models/alias';
|
||||
import verifyToken from './middlewares/token';
|
||||
import PageOrder from '../models/pageOrder';
|
||||
import Page from '../models/page';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
@ -32,9 +34,27 @@ router.get('*', verifyToken, async (req: Request, res: Response) => {
|
|||
|
||||
const pageParent = await page.getParent();
|
||||
|
||||
let previousPage;
|
||||
|
||||
let nextPage;
|
||||
|
||||
const previousPageId = await PageOrder.getPreviousNavigationPage(alias.id);
|
||||
|
||||
const nextPageId = await PageOrder.getNextNavigationPage(alias.id);
|
||||
|
||||
if (previousPageId){
|
||||
previousPage = await Page.get(previousPageId);
|
||||
}
|
||||
|
||||
if (nextPageId) {
|
||||
nextPage = await Page.get(nextPageId);
|
||||
}
|
||||
|
||||
res.render('pages/page', {
|
||||
page,
|
||||
pageParent,
|
||||
previousPage,
|
||||
nextPage,
|
||||
config: req.app.locals.config,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -158,8 +158,8 @@ router.delete('/page/:id', async (req: Request, res: Response) => {
|
|||
}
|
||||
|
||||
const parentPageOrder = await PagesOrder.get(page._parent);
|
||||
const pageBeforeId = parentPageOrder.getPageBefore(page._id);
|
||||
const pageAfterId = parentPageOrder.getPageAfter(page._id);
|
||||
const pageBeforeId = parentPageOrder.getSubPageBefore(page._id);
|
||||
const pageAfterId = parentPageOrder.getSubPageAfter(page._id);
|
||||
|
||||
let pageToRedirect;
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ import Pages from '../controllers/pages';
|
|||
import PagesOrder from '../controllers/pagesOrder';
|
||||
import verifyToken from './middlewares/token';
|
||||
import allowEdit from './middlewares/locals';
|
||||
import PageOrder from '../models/pageOrder';
|
||||
import Page from '../models/page';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
@ -62,10 +64,28 @@ router.get('/page/:id', verifyToken, async (req: Request, res: Response, next: N
|
|||
|
||||
const pageParent = await page.parent;
|
||||
|
||||
let previousPage;
|
||||
|
||||
let nextPage;
|
||||
|
||||
const previousPageId = await PageOrder.getPreviousNavigationPage(pageId);
|
||||
|
||||
const nextPageId = await PageOrder.getNextNavigationPage(pageId);
|
||||
|
||||
if (previousPageId) {
|
||||
previousPage = await Page.get(previousPageId);
|
||||
}
|
||||
|
||||
if (nextPageId) {
|
||||
nextPage = await Page.get(nextPageId);
|
||||
}
|
||||
|
||||
res.render('pages/page', {
|
||||
page,
|
||||
pageParent,
|
||||
config: req.app.locals.config,
|
||||
previousPage,
|
||||
nextPage,
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(404);
|
||||
|
|
21
src/backend/views/components/navigator.twig
Normal file
21
src/backend/views/components/navigator.twig
Normal file
|
@ -0,0 +1,21 @@
|
|||
{% set mainClass = 'navigator' %}
|
||||
|
||||
|
||||
{% set tag = 'div' %}
|
||||
|
||||
{% if url is not empty %}
|
||||
{% set tag = 'a' %}
|
||||
{% endif %}
|
||||
|
||||
<{{tag}}
|
||||
{{ name is not empty ? 'name="' ~ name ~ '"': '' }}
|
||||
class="{{ mainClass }} {{ mainClass }}--{{ direction|default('previous') }} {{ class ?? '' }}"
|
||||
{{ url is not empty ? 'href="' ~ url ~ '"' : '' }}
|
||||
>
|
||||
<div class="{{mainClass}}__direction">
|
||||
{{ direction }}
|
||||
</div>
|
||||
<div class="{{mainClass}}__label">
|
||||
{{ label }}
|
||||
</div>
|
||||
</{{tag}}>
|
|
@ -23,6 +23,9 @@
|
|||
{% include 'components/button.twig' with {label: 'Edit', icon: 'pencil', size: 'small', url: '/page/edit/' ~ page._id, class: 'page__header-button'} %}
|
||||
{% endif %}
|
||||
</header>
|
||||
<script>
|
||||
console.log({{prev.uri}})
|
||||
</script>
|
||||
<h1 class="page__title">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
|
@ -39,7 +42,17 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
<footer>
|
||||
<footer class="page_footer">
|
||||
<div class="navigator_wrapper">
|
||||
{% if previousPage %}
|
||||
{% include 'components/navigator.twig' with {label: previousPage.title, direction: 'previous', url: '/' ~ previousPage.uri} %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="navigator_wrapper">
|
||||
{% if nextPage %}
|
||||
{% include 'components/navigator.twig' with {label: nextPage.title, direction: 'next', url: '/' ~ nextPage.uri} %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
|
|
46
src/frontend/styles/components/navigator.pcss
Normal file
46
src/frontend/styles/components/navigator.pcss
Normal file
|
@ -0,0 +1,46 @@
|
|||
.navigator {
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: var(--color-bg-navigation);
|
||||
border-radius: 10px;
|
||||
padding: 12px 16px 12px 16px;
|
||||
color: black;
|
||||
width: max-content;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
|
||||
&--previous {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&--next {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
&__direction {
|
||||
text-transform: capitalize;
|
||||
color: var(--color-direction-navigation);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&__label {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.navigator_wrapper {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page_footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
@import './components/auth.pcss';
|
||||
@import './components/button.pcss';
|
||||
@import './components/sidebar.pcss';
|
||||
@import './components/navigator.pcss';
|
||||
|
||||
body {
|
||||
font-family: system-ui, Helvetica, Arial, Verdana;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
:root {
|
||||
--color-text-main: #313649;
|
||||
--color-text-second: #5d6068;
|
||||
--color-direction-navigation: #717682;
|
||||
--color-line-gray: #E8E8EB;
|
||||
--color-link-active: #2071cc;
|
||||
--color-link-hover: #F3F6F8;
|
||||
|
@ -19,6 +20,8 @@
|
|||
--color-button-warning-hover: #D65151;
|
||||
--color-button-warning-active: #BD4848;
|
||||
|
||||
--color-bg-navigation: #F3F6F8;
|
||||
|
||||
|
||||
/**
|
||||
* Site layout sizes
|
||||
|
@ -79,7 +82,7 @@
|
|||
|
||||
--squircle {
|
||||
border-radius: 8px;
|
||||
|
||||
|
||||
@supports(-webkit-mask-box-image: url('')){
|
||||
border-radius: 0;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10.3872C0 1.83334 1.83334 0 10.3872 0H13.6128C22.1667 0 24 1.83334 24 10.3872V13.6128C24 22.1667 22.1667 24 13.6128 24H10.3872C1.83334 24 0 22.1667 0 13.6128V10.3872Z' fill='black'/%3E%3C/svg%3E%0A") 48% 41% 37.9% 53.3%;;
|
||||
|
@ -95,4 +98,4 @@
|
|||
@custom-media --tablet all and (min-width: 980px) and (max-width: 1050px);
|
||||
@custom-media --mobile all and (max-width: 980px);
|
||||
@custom-media --retina all and (-webkit-min-device-pixel-ratio: 1.5);
|
||||
@custom-media --can-hover all and (hover:hover)
|
||||
@custom-media --can-hover all and (hover:hover)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue