mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
Merge branch 'master' into channels
This commit is contained in:
commit
4e1f9bfc31
102
webui-src/app/boards/board.css
Normal file
102
webui-src/app/boards/board.css
Normal file
@ -0,0 +1,102 @@
|
||||
.board-node-panel {
|
||||
position: relative;
|
||||
bottom: 200px;
|
||||
margin-left: 200px;
|
||||
animation: fadein 0.5s;
|
||||
}
|
||||
|
||||
/* subject */
|
||||
table.boards th:nth-child(1) {
|
||||
width: 50%;
|
||||
text-align: start;
|
||||
}
|
||||
/* subject */
|
||||
table.boards td:nth-child(1) {
|
||||
text-align: start;
|
||||
/* Truncate text with '...' */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
table.boards tr:hover {
|
||||
background-color: #eef3f6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
table.boards tr.hidden{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#searchboard{
|
||||
position:relative;
|
||||
margin-left: 250px;
|
||||
}
|
||||
|
||||
img.boardpic {
|
||||
float: left;
|
||||
height: 150px;
|
||||
width:150px;
|
||||
padding: 25px;
|
||||
}
|
||||
#boarddetails{
|
||||
position: relative;
|
||||
margin-left: 150px;
|
||||
}
|
||||
.p{
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#toggleunsub{
|
||||
position: relative;
|
||||
background: gray;
|
||||
}
|
||||
|
||||
#grid{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
gap: 100px;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 2px solid gray;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
.card-img{
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
.card-title{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
/* subject */
|
||||
table.comments th{
|
||||
height: 40px;
|
||||
}
|
||||
table.comments th:nth-child(1) {
|
||||
width: 40%;
|
||||
}
|
||||
table.comments td {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
table.comments td:nth-child(1){
|
||||
border: 3px solid lightskyblue;
|
||||
border-radius: 25px;
|
||||
|
||||
}
|
||||
table.comments tr{
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
#options{
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
font-size: medium;
|
||||
margin-left: 20px;
|
||||
height: 40px;
|
||||
}
|
||||
142
webui-src/app/boards/board_view.js
Normal file
142
webui-src/app/boards/board_view.js
Normal file
@ -0,0 +1,142 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
const util = require('boards/boards_util');
|
||||
const Data = util.Data;
|
||||
const peopleUtil = require('people/people_util');
|
||||
|
||||
const BoardView = () => {
|
||||
let bname = '';
|
||||
let bimage = '';
|
||||
let bauthor = '';
|
||||
let bsubscribed = {};
|
||||
let bposts = 0;
|
||||
let plist = {};
|
||||
let createDate = {};
|
||||
let lastActivity = {};
|
||||
return {
|
||||
oninit: (v) => {
|
||||
if (Data.DisplayBoards[v.attrs.id]) {
|
||||
bname = Data.DisplayBoards[v.attrs.id].name;
|
||||
bimage = Data.DisplayBoards[v.attrs.id].image;
|
||||
if (rs.userList.userMap[Data.DisplayBoards[v.attrs.id].author]) {
|
||||
bauthor = rs.userList.userMap[Data.DisplayBoards[v.attrs.id].author];
|
||||
} else if (Number(Data.DisplayBoards[v.attrs.id].author) === 0) {
|
||||
bauthor = 'No Contact Author';
|
||||
} else {
|
||||
bauthor = 'Unknown';
|
||||
}
|
||||
bsubscribed = Data.DisplayBoards[v.attrs.id].isSubscribed;
|
||||
bposts = Data.DisplayBoards[v.attrs.id].posts;
|
||||
createDate = Data.DisplayBoards[v.attrs.id].created;
|
||||
lastActivity = Data.DisplayBoards[v.attrs.id].activity;
|
||||
}
|
||||
if (Data.Posts[v.attrs.id]) {
|
||||
plist = Data.Posts[v.attrs.id];
|
||||
}
|
||||
},
|
||||
view: (v) =>
|
||||
m(
|
||||
'.widget',
|
||||
{
|
||||
key: v.attrs.id,
|
||||
},
|
||||
[
|
||||
m(
|
||||
'a[title=Back]',
|
||||
{
|
||||
onclick: () =>
|
||||
m.route.set('/boards/:tab', {
|
||||
tab: m.route.param().tab,
|
||||
}),
|
||||
},
|
||||
m('i.fas.fa-arrow-left')
|
||||
),
|
||||
m('h3', bname),
|
||||
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: async () => {
|
||||
const res = await rs.rsJsonApiRequest('/rsposted/subscribeToBoard', {
|
||||
boardId: v.attrs.id,
|
||||
subscribe: !bsubscribed,
|
||||
});
|
||||
if (res.body.retval) {
|
||||
bsubscribed = !bsubscribed;
|
||||
Data.DisplayBoards[v.attrs.id].isSubscribed = bsubscribed;
|
||||
}
|
||||
},
|
||||
},
|
||||
bsubscribed ? 'Subscribed' : 'Subscribe'
|
||||
),
|
||||
m('img.boardpic', {
|
||||
src: 'data:image/png;base64,' + bimage.mData.base64,
|
||||
}),
|
||||
m('[id=boarddetails]', [
|
||||
m('p', m('b', 'Posts: '), bposts),
|
||||
m(
|
||||
'p',
|
||||
m('b', 'Date created: '),
|
||||
typeof createDate === 'object'
|
||||
? new Date(createDate.xint64 * 1000).toLocaleString()
|
||||
: 'undefined'
|
||||
),
|
||||
m('p', m('b', 'Admin: '), bauthor),
|
||||
m(
|
||||
'p',
|
||||
m('b', 'Last activity: '),
|
||||
typeof lastActivity === 'object'
|
||||
? new Date(lastActivity.xint64 * 1000).toLocaleString()
|
||||
: 'undefined'
|
||||
),
|
||||
]),
|
||||
m('hr'),
|
||||
m('boarddesc', m('b', 'Description: '), Data.DisplayBoards[v.attrs.id].description),
|
||||
m('hr'),
|
||||
m(
|
||||
'postdetails',
|
||||
{
|
||||
style: 'display:' + (bsubscribed ? 'block' : 'none'),
|
||||
},
|
||||
m('h3', 'Posts'),
|
||||
|
||||
m(
|
||||
'[id=grid]',
|
||||
Object.keys(plist).map((key, index) => [
|
||||
m(
|
||||
'div',
|
||||
{
|
||||
class: 'card',
|
||||
style: 'display: ' + (plist[key].isSearched? 'block': 'none'),
|
||||
onclick: () => {
|
||||
m.route.set('/boards/:tab/:mGroupId/:mMsgId', {
|
||||
tab: m.route.param().tab,
|
||||
mGroupId: v.attrs.id,
|
||||
mMsgId: key,
|
||||
});
|
||||
},
|
||||
},
|
||||
[
|
||||
m('img', {
|
||||
class: 'card-img',
|
||||
src: 'data:image/png;base64,' + plist[key].post.mThumbnail.mData.base64,
|
||||
|
||||
alt: 'No Thumbnail',
|
||||
}),
|
||||
m('div', { class: 'card-info' }, [
|
||||
m('h4', { class: 'card-title' }, plist[key].post.mMeta.mMsgName),
|
||||
]),
|
||||
]
|
||||
),
|
||||
])
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
BoardView,
|
||||
};
|
||||
80
webui-src/app/boards/boards.js
Normal file
80
webui-src/app/boards/boards.js
Normal file
@ -0,0 +1,80 @@
|
||||
const m = require('mithril');
|
||||
const widget = require('widgets');
|
||||
const rs = require('rswebui');
|
||||
const util = require('boards/boards_util');
|
||||
const viewUtil = require('boards/board_view');
|
||||
|
||||
const getBoards =
|
||||
{
|
||||
All : [],
|
||||
PopularBoards : [],
|
||||
SubscribedBoards : [],
|
||||
MyBoards : [],
|
||||
async load(){
|
||||
const res = await rs.rsJsonApiRequest('/rsPosted/getBoardsSummaries');
|
||||
const data = res.body;
|
||||
getBoards.All = data.groupInfo;
|
||||
getBoards.PopularBoards = getBoards.All;
|
||||
getBoards.SubscribedBoards = getBoards.All.filter(
|
||||
(board) =>
|
||||
board.mSubscribeFlags === util.GROUP_SUBSCRIBE_SUBSCRIBED
|
||||
);
|
||||
getBoards.MyBoards = getBoards.All.filter(
|
||||
(board) => board.mSubscribeFlags === util.GROUP_MY_BOARD
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const sections = {
|
||||
MyBoards: require('boards/my_boards'),
|
||||
SubscribedBoards: require('boards/subscribed_boards'),
|
||||
PopularBoards: require('boards/popular_boards'),
|
||||
OtherBoards: require('boards/other_boards')
|
||||
};
|
||||
|
||||
const Layout = {
|
||||
oninit : () => {
|
||||
rs.setBackgroundTask(getBoards.load, 5000, () => {
|
||||
});
|
||||
},
|
||||
// onupdate: getBoards.load,
|
||||
view: (vnode) =>
|
||||
m('.tab-page', [
|
||||
Object.prototype.hasOwnProperty.call(vnode.attrs.pathInfo, 'mMsgId')
|
||||
? ''
|
||||
: Object.prototype.hasOwnProperty.call(vnode.attrs.pathInfo, 'mGroupId')
|
||||
? m(util.SearchBar, {
|
||||
category: 'posts',
|
||||
boardId: vnode.attrs.pathInfo.mGroupId
|
||||
})
|
||||
: m(util.SearchBar, {
|
||||
category: 'boards'
|
||||
}),
|
||||
m(widget.Sidebar, {
|
||||
tabs: Object.keys(sections),
|
||||
baseRoute: '/boards/',
|
||||
}),
|
||||
m('.board-node-panel',
|
||||
Object.prototype.hasOwnProperty.call(vnode.attrs.pathInfo, 'mMsgId')
|
||||
? m(viewUtil.PostView, {
|
||||
msgId: vnode.attrs.pathInfo.mMsgId,
|
||||
boardId: vnode.attrs.pathInfo.mGroupId,
|
||||
})
|
||||
: Object.prototype.hasOwnProperty.call(vnode.attrs.pathInfo, 'mGroupId')
|
||||
? m(viewUtil.BoardView, {
|
||||
id: vnode.attrs.pathInfo.mGroupId,
|
||||
})
|
||||
: m(sections[vnode.attrs.pathInfo.tab], {
|
||||
list: getBoards[vnode.attrs.pathInfo.tab],
|
||||
})
|
||||
),
|
||||
]),
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
view: (vnode) => {
|
||||
return m(Layout, {
|
||||
pathInfo: vnode.attrs,
|
||||
});
|
||||
},
|
||||
};
|
||||
159
webui-src/app/boards/boards_util.js
Normal file
159
webui-src/app/boards/boards_util.js
Normal file
@ -0,0 +1,159 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
|
||||
const GROUP_SUBSCRIBE_ADMIN = 0x01;// means: you have the admin key for this group
|
||||
const GROUP_SUBSCRIBE_PUBLISH = 0x02;// means: you have the publish key for thiss group. Typical use: publish key in channels are shared with specific friends.
|
||||
const GROUP_SUBSCRIBE_SUBSCRIBED = 0x04;// means: you are subscribed to a group, which makes you a source for this group to your friend nodes.
|
||||
const GROUP_SUBSCRIBE_NOT_SUBSCRIBED = 0x08;
|
||||
const GROUP_MY_BOARD = GROUP_SUBSCRIBE_ADMIN + GROUP_SUBSCRIBE_SUBSCRIBED + GROUP_SUBSCRIBE_PUBLISH;
|
||||
const GXS_VOTE_DOWN = 0x0001;
|
||||
const GXS_VOTE_UP = 0x0002;
|
||||
|
||||
const Data = {
|
||||
DisplayBoards: {},
|
||||
Posts: {},
|
||||
Comments: {},
|
||||
};
|
||||
|
||||
async function updateContent(content, boardid) {
|
||||
const res = await rs.rsJsonApiRequest('/rsPosted/getBoardContent', {
|
||||
boardId: boardid,
|
||||
contentsIds: [content.mMsgId],
|
||||
});
|
||||
if (res.body.retval && res.body.posts.length > 0) {
|
||||
Data.Posts[boardid][content.mMsgId] = { post: res.body.posts[0], isSearched: true };
|
||||
} else if (res.body.retval && res.body.comments.length > 0) {
|
||||
if (Data.Comments[content.mThreadId] === undefined) {
|
||||
Data.Comments[content.mThreadId] = {};
|
||||
}
|
||||
Data.Comments[content.mThreadId][content.mMsgId] = res.body.comments[0];
|
||||
} else if (res.body.retval && res.body.votes.length > 0) {
|
||||
const vote = res.body.votes[0];
|
||||
if (
|
||||
Data.Comments[vote.mMeta.mThreadId] &&
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId]
|
||||
) {
|
||||
if (vote.mVoteType === GXS_VOTE_UP) {
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId].mUpVotes += 1;
|
||||
}
|
||||
if (vote.mVoteType === GXS_VOTE_DOWN) {
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId].mDownVotes += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateDisplayBoards(keyid, details) {
|
||||
const res1 = await rs.rsJsonApiRequest('/rsPosted/getBoardsInfo', {
|
||||
boardsIds: [keyid],
|
||||
});
|
||||
details = res1.body.boardsInfo[0];
|
||||
Data.DisplayBoards[keyid] = {
|
||||
name: details.mMeta.mGroupName,
|
||||
isSearched: true,
|
||||
description: details.mDescription,
|
||||
image: details.mGroupImage,
|
||||
author: details.mMeta.mAuthorId,
|
||||
isSubscribed:
|
||||
details.mMeta.mSubscribeFlags === GROUP_SUBSCRIBE_SUBSCRIBED ||
|
||||
details.mMeta.mSubscribeFlags === GROUP_MY_BOARD,
|
||||
posts: details.mMeta.mVisibleMsgCount,
|
||||
activity: details.mMeta.mLastPost,
|
||||
created: details.mMeta.mPublishTs,
|
||||
all: details,
|
||||
};
|
||||
|
||||
if (Data.Posts[keyid] === undefined) {
|
||||
Data.Posts[keyid] = {};
|
||||
}
|
||||
|
||||
/*const res2 = await rs.rsJsonApiRequest('/rsPosted/getContentSummaries', {
|
||||
boardId: keyid,
|
||||
});
|
||||
|
||||
if (res2.body.retval) {
|
||||
res2.body.summaries.map((content) => {
|
||||
updateContent(content, keyid);
|
||||
});
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
const DisplayBoardsFromList = () => {
|
||||
return {
|
||||
oninit: (v) => {},
|
||||
view: (v) =>
|
||||
m(
|
||||
'tr',
|
||||
{
|
||||
key: v.attrs.id,
|
||||
class:
|
||||
Data.DisplayBoards[v.attrs.id] && Data.DisplayBoards[v.attrs.id].isSearched
|
||||
? ''
|
||||
: 'hidden',
|
||||
onclick: () => {
|
||||
m.route.set('/boards/:tab/:mGroupId', {
|
||||
tab: v.attrs.category,
|
||||
mGroupId: v.attrs.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
[m('td', Data.DisplayBoards[v.attrs.id] ? Data.DisplayBoards[v.attrs.id].name : '')]
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const BoardSummary = () => {
|
||||
let keyid = {};
|
||||
return {
|
||||
oninit: (v) => {
|
||||
keyid = v.attrs.details.mGroupId;
|
||||
updateDisplayBoards(keyid);
|
||||
},
|
||||
|
||||
view: (v) => {},
|
||||
};
|
||||
};
|
||||
|
||||
const BoardTable = () => {
|
||||
return {
|
||||
oninit: (v) => {},
|
||||
view: (v) => m('table.boards', [m('tr', [m('th', 'Board Name')]), v.children]),
|
||||
};
|
||||
};
|
||||
|
||||
const SearchBar = () => {
|
||||
let searchString = '';
|
||||
return {
|
||||
view: (v) =>
|
||||
m('input[type=text][id=searchboard][placeholder=Search Subject].searchbar', {
|
||||
value: searchString,
|
||||
oninput: (e) => {
|
||||
searchString = e.target.value.toLowerCase();
|
||||
for (const hash in Data.DisplayBoards) {
|
||||
if (Data.DisplayBoards[hash].name.toLowerCase().indexOf(searchString) > -1) {
|
||||
Data.DisplayBoards[hash].isSearched = true;
|
||||
} else {
|
||||
Data.DisplayBoards[hash].isSearched = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Data,
|
||||
SearchBar,
|
||||
BoardSummary,
|
||||
DisplayBoardsFromList,
|
||||
updateDisplayBoards,
|
||||
BoardTable,
|
||||
GROUP_SUBSCRIBE_ADMIN,
|
||||
GROUP_SUBSCRIBE_NOT_SUBSCRIBED,
|
||||
GROUP_SUBSCRIBE_PUBLISH,
|
||||
GROUP_SUBSCRIBE_SUBSCRIBED,
|
||||
GROUP_MY_BOARD,
|
||||
GXS_VOTE_DOWN,
|
||||
GXS_VOTE_UP,
|
||||
};
|
||||
32
webui-src/app/boards/my_boards.js
Normal file
32
webui-src/app/boards/my_boards.js
Normal file
@ -0,0 +1,32 @@
|
||||
const m = require('mithril');
|
||||
const util = require('boards/boards_util');
|
||||
|
||||
const Layout = () => {
|
||||
return {
|
||||
view: (v) => [
|
||||
m('.widget', [
|
||||
m('h3', 'My Boards'),
|
||||
m('hr'),
|
||||
m(
|
||||
util.BoardTable,
|
||||
m('tbody', [
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.BoardSummary, {
|
||||
details: board,
|
||||
category: 'MyBoards',
|
||||
})
|
||||
),
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.DisplayBoardsFromList, {
|
||||
id: board.mGroupId,
|
||||
category: 'MyBoards',
|
||||
})
|
||||
),
|
||||
])
|
||||
),
|
||||
]),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Layout();
|
||||
11
webui-src/app/boards/other_boards.js
Normal file
11
webui-src/app/boards/other_boards.js
Normal file
@ -0,0 +1,11 @@
|
||||
const m = require('mithril');
|
||||
|
||||
const Layout = () => {
|
||||
return{
|
||||
view: () => [
|
||||
m('.widget', [m('h2', 'Other Boards'), m('hr'), ])
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Layout();
|
||||
33
webui-src/app/boards/popular_boards.js
Normal file
33
webui-src/app/boards/popular_boards.js
Normal file
@ -0,0 +1,33 @@
|
||||
const m = require('mithril');
|
||||
const util = require('boards/boards_util');
|
||||
|
||||
const Layout = () => {
|
||||
return {
|
||||
view: (v) => [
|
||||
m('.widget', [
|
||||
m('h3', 'Popular Boards'),
|
||||
m('hr'),
|
||||
m(
|
||||
util.BoardTable,
|
||||
m('tbody', [
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.BoardSummary, {
|
||||
details: board,
|
||||
category: 'PopularBoards',
|
||||
}),
|
||||
),
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.DisplayBoardsFromList, {
|
||||
id: board.mGroupId,
|
||||
category: 'PopularBoards',
|
||||
}),
|
||||
),
|
||||
])
|
||||
),
|
||||
]),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Layout;
|
||||
|
||||
33
webui-src/app/boards/subscribed_boards.js
Normal file
33
webui-src/app/boards/subscribed_boards.js
Normal file
@ -0,0 +1,33 @@
|
||||
const m = require('mithril');
|
||||
const util = require('boards/boards_util');
|
||||
|
||||
const Layout = () => {
|
||||
return {
|
||||
view: (v) => [
|
||||
m('.widget', [
|
||||
m('h3', 'Subscribed Boards'),
|
||||
m('hr'),
|
||||
m(
|
||||
util.BoardTable,
|
||||
m('tbody', [
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.BoardSummary, {
|
||||
details: board,
|
||||
category: 'SubscribedBoards',
|
||||
}),
|
||||
),
|
||||
v.attrs.list.map((board) =>
|
||||
m(util.DisplayBoardsFromList, {
|
||||
id: board.mGroupId,
|
||||
category: 'SubscribedBoards',
|
||||
}),
|
||||
),
|
||||
])
|
||||
),
|
||||
]),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Layout;
|
||||
|
||||
@ -9,6 +9,7 @@ const mail = require('mail/mail_resolver');
|
||||
const files = require('files/files_resolver');
|
||||
const channels = require('channels/channels');
|
||||
const forums = require('forums/forums');
|
||||
const boards = require('boards/boards');
|
||||
const config = require('config/config_resolver');
|
||||
|
||||
const navIcon = {
|
||||
@ -20,6 +21,7 @@ const navIcon = {
|
||||
files: m('i.fas.fa-folder-open.sidenav-icon'),
|
||||
channels: m('i.fas.fa-tv.sidenav-icon'),
|
||||
forums: m('i.fas.fa-bullhorn.sidenav-icon'),
|
||||
boards: m('i.fas.fa-globe.sidenav-icon'),
|
||||
config: m('i.fas.fa-cogs.sidenav-icon'),
|
||||
};
|
||||
|
||||
@ -56,7 +58,8 @@ const Layout = () => {
|
||||
mail: '/mail/inbox',
|
||||
files: '/files/files',
|
||||
channels: '/channels/MyChannels',
|
||||
forums: 'forums/MyForums',
|
||||
forums: '/forums/MyForums',
|
||||
boards: '/boards/MyBoards',
|
||||
config: '/config/network',
|
||||
},
|
||||
}),
|
||||
@ -112,8 +115,19 @@ m.route(document.getElementById('main'), '/', {
|
||||
'/forums/:tab/:mGroupId': {
|
||||
render: (v) => m(Layout, m(forums, v.attrs)),
|
||||
},
|
||||
|
||||
'/forums/:tab/:mGroupId/:mMsgId': {
|
||||
render: (v) => m(Layout, m(forums, v.attrs)),
|
||||
|
||||
'/boards/:tab': {
|
||||
render: (v) => m(Layout, m(boards, v.attrs)),
|
||||
},
|
||||
'/boards/:tab/:mGroupId': {
|
||||
render: (v) => m(Layout, m(boards, v.attrs)),
|
||||
},
|
||||
'/boards/:tab/:mGroupId/:mMsgId': {
|
||||
render: (v) => m(Layout, m(boards, v.attrs)),
|
||||
|
||||
},
|
||||
'/config/:tab': {
|
||||
render: (v) => m(Layout, m(config, v.attrs)),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user