1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-04-01 21:24:45 +02:00

Server: Add support for sidebar in user pages

This commit is contained in:
Laurent Cozic 2022-03-03 11:32:35 +00:00
parent 07f128ae95
commit 053dbabf74
4 changed files with 80 additions and 37 deletions
packages/server/src

@ -5,22 +5,12 @@ import config from '../config';
import { filename } from '@joplin/lib/path-utils';
import { NotificationView } from '../utils/types';
import { User } from '../services/database/types';
import { makeUrl, SubPath, urlMatchesSchema, UrlType } from '../utils/routeUtils';
import { makeUrl, SubPath, UrlType } from '../utils/routeUtils';
import MarkdownIt = require('markdown-it');
import { headerAnchor } from '@joplin/renderer';
import { _ } from '@joplin/lib/locale';
import { adminDashboardUrl, adminEmailsUrl, adminTasksUrl, adminUserDeletionsUrl, adminUsersUrl, changesUrl, homeUrl, itemsUrl } from '../utils/urlUtils';
type MenuItemSelectedCondition = (selectedUrl: SubPath)=> boolean;
export interface MenuItem {
title: string;
url?: string;
children?: MenuItem[];
selected?: boolean;
icon?: string;
selectedCondition?: MenuItemSelectedCondition;
}
import { MenuItem, setSelectedMenu } from '../utils/views/menu';
export interface RenderOptions {
partials?: any;
@ -40,6 +30,7 @@ export interface View {
cssFiles?: string[];
jsFiles?: string[];
strings?: Record<string, string>; // List of translatable strings
sidebarMenu?: MenuItem[];
}
interface GlobalParams {
@ -111,22 +102,6 @@ export default class MustacheService {
return `${config().layoutDir}/${name}.mustache`;
}
private setSelectedMenu(selectedPath: SubPath, menuItems: MenuItem[]) {
if (!selectedPath) return;
if (!menuItems) return;
for (const menuItem of menuItems) {
if (menuItem.url) {
if (menuItem.selectedCondition) {
menuItem.selected = menuItem.selectedCondition(selectedPath);
} else {
menuItem.selected = urlMatchesSchema(menuItem.url, selectedPath.schema);
}
}
this.setSelectedMenu(selectedPath, menuItem.children);
}
}
private makeAdminMenu(selectedPath: SubPath): MenuItem[] {
const output: MenuItem[] = [
{
@ -156,9 +131,7 @@ export default class MustacheService {
},
];
this.setSelectedMenu(selectedPath, output);
return output;
return setSelectedMenu(selectedPath, output);
}
private makeNavbar(selectedPath: SubPath, isAdmin: boolean): MenuItem[] {
@ -190,9 +163,7 @@ export default class MustacheService {
]);
}
this.setSelectedMenu(selectedPath, output);
return output;
return setSelectedMenu(selectedPath, output);
}
private get defaultLayoutOptions(): GlobalParams {
@ -318,6 +289,7 @@ export default class MustacheService {
cssFiles: cssFiles,
jsFiles: jsFiles,
navbar: view.navbar,
sidebarMenu: view.sidebarMenu,
...view.content,
};

@ -0,0 +1,39 @@
import { SubPath, urlMatchesSchema } from '../routeUtils';
export type MenuItemSelectedCondition = (selectedUrl: SubPath)=> boolean;
export interface MenuItem {
title: string;
url?: string;
children?: MenuItem[];
selected?: boolean;
icon?: string;
selectedCondition?: MenuItemSelectedCondition;
}
export const setSelectedMenu = (selectedPath: SubPath, menuItems: MenuItem[]) => {
if (!selectedPath) return menuItems;
if (!menuItems) return menuItems;
menuItems = menuItems.slice();
for (let i = 0; i < menuItems.length; i++) {
const menuItem = menuItems[i];
let selected = menuItem.selected;
if (menuItem.url) {
if (menuItem.selectedCondition) {
selected = menuItem.selectedCondition(selectedPath);
} else {
selected = urlMatchesSchema(menuItem.url, selectedPath.schema);
}
}
menuItems[i] = {
...menuItem,
selected,
children: setSelectedMenu(selectedPath, menuItem.children),
};
}
return menuItems;
};

@ -25,13 +25,25 @@
<div class="container main-container">
{{> notifications}}
{{! ADMIN PAGE }}
{{#global.isAdminPage}}
{{> adminLayout}}
{{/global.isAdminPage}}
{{^global.isAdminPage}}
{{{contentHtml}}}
{{/global.isAdminPage}}
{{! USER PAGE - WITH SIDEBAR }}
{{^sidebarMenu}}
{{^global.isAdminPage}}
{{{contentHtml}}}
{{/global.isAdminPage}}
{{/sidebarMenu}}
{{! USER PAGE - NO SIDEBAR }}
{{#sidebarMenu}}
{{> sidebarLayout}}
{{/sidebarMenu}}
</div>
</main>
{{> footer}}

@ -0,0 +1,20 @@
<div style="display: flex; flex-direction: row;">
<div style="display: flex; margin-right: 3rem; background-color: #f5f5f5; padding: 1.5rem;">
<aside class="menu">
{{#sidebarMenu}}
<p class="menu-label">{{title}}</p>
<ul class="menu-list">
{{#children}}
<li><a href="{{{url}}}" class="{{#selected}}is-active{{/selected}}">{{title}}</a></li>
{{/children}}
</ul>
{{/sidebarMenu}}
</aside>
</div>
<div style="display: flex; flex: 1;">
<div>
{{{contentHtml}}}
</div>
</div>
</div>