From fe6b2cafd38e39ba549c992dd5356b1182321e46 Mon Sep 17 00:00:00 2001 From: Ruslan Semak Date: Wed, 23 Apr 2025 11:58:38 +0300 Subject: [PATCH] feat: Added custom mdi icons for pages --- client/components/admin/admin-pages.vue | 5 ++++ client/graph/admin/pages/pages-query-list.gql | 1 + .../graph/common/common-pages-query-list.gql | 1 + .../graph/common/common-pages-query-tree.gql | 2 ++ .../themes/default/components/nav-sidebar.vue | 9 ++++-- server/db/migrations/2.5.132.js | 13 ++++++++ server/graph/resolvers/page.js | 30 +------------------ server/graph/schemas/page.graphql | 5 +++- server/jobs/rebuild-tree.js | 3 +- 9 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 server/db/migrations/2.5.132.js diff --git a/client/components/admin/admin-pages.vue b/client/components/admin/admin-pages.vue index 61aaa1cd..91a050ab 100644 --- a/client/components/admin/admin-pages.vue +++ b/client/components/admin/admin-pages.vue @@ -94,6 +94,9 @@ :class="{'drag-over': dragOverIndex === props.index}" ) td.text-xs-right {{ props.item.id }} + td.text-xs-right {{ props.item.icon }} + td + v-icon(v-if='props.item.icon') mdi-{{ props.item.icon }} td.text-xs-right {{ props.item.orderPriority }} td .body-2: strong {{ props.item.title }} @@ -123,6 +126,8 @@ export default { pageTotal: 0, headers: [ { text: 'ID', value: 'id', width: 80, sortable: true }, + { text: 'Icon name', value: 'icon' }, + { text: 'Icon', value: 'icon' }, { text: 'Order', value: 'orderPriority', width: 100 }, { text: 'Title', value: 'title' }, { text: 'Path', value: 'path' }, diff --git a/client/graph/admin/pages/pages-query-list.gql b/client/graph/admin/pages/pages-query-list.gql index 3194fc19..56ed00bd 100644 --- a/client/graph/admin/pages/pages-query-list.gql +++ b/client/graph/admin/pages/pages-query-list.gql @@ -10,6 +10,7 @@ query { isPublished isPrivate orderPriority + icon privateNS createdAt updatedAt diff --git a/client/graph/common/common-pages-query-list.gql b/client/graph/common/common-pages-query-list.gql index e4d71756..994d3289 100644 --- a/client/graph/common/common-pages-query-list.gql +++ b/client/graph/common/common-pages-query-list.gql @@ -5,6 +5,7 @@ query ($limit: Int, $orderBy: PageOrderBy, $orderByDirection: PageOrderByDirecti locale path title + icon description createdAt updatedAt diff --git a/client/graph/common/common-pages-query-tree.gql b/client/graph/common/common-pages-query-tree.gql index f1ee4eab..b3be011a 100644 --- a/client/graph/common/common-pages-query-tree.gql +++ b/client/graph/common/common-pages-query-tree.gql @@ -4,6 +4,8 @@ query ($parent: Int!, $mode: PageTreeMode!, $locale: String!) { id path title + icon + orderPriority isFolder pageId parent diff --git a/client/themes/default/components/nav-sidebar.vue b/client/themes/default/components/nav-sidebar.vue index 63831841..0c691958 100644 --- a/client/themes/default/components/nav-sidebar.vue +++ b/client/themes/default/components/nav-sidebar.vue @@ -67,7 +67,8 @@ @update:active='activeTreeItem' ) template(v-slot:prepend="{ item, open }") - v-icon(v-if="!item.children") mdi-text-box + v-icon(v-if="!item.children && item.icon") mdi-{{ item.icon }} + v-icon(v-else-if="!item.children && !item.icon") mdi-text-box v-icon(v-else-if="open") mdi-folder-open v-icon(v-else) mdi-folder template(v-slot:label="{ item }") @@ -272,9 +273,9 @@ export default { }, pageItem2TreeItem(item, level) { if (item.isFolder) { - return { id: item.id, level: level, pageId: item.pageId, path: item.path, locale: item.locale, name: item.title, children: [] } + return { id: item.id, icon: item.icon, level: level, pageId: item.pageId, path: item.path, locale: item.locale, name: item.title, children: [] } } else { - return { id: item.id, level: level, path: item.path, locale: item.locale, name: item.title } + return { id: item.id, icon: item.icon, level: level, path: item.path, locale: item.locale, name: item.title } } }, activeTreeItem([id]) { @@ -342,6 +343,7 @@ export default { id path title + icon isFolder pageId parent @@ -356,6 +358,7 @@ export default { locale: this.locale } }) + return _.get(resp, 'data.pages.tree', []) } }, diff --git a/server/db/migrations/2.5.132.js b/server/db/migrations/2.5.132.js new file mode 100644 index 00000000..abedfd6e --- /dev/null +++ b/server/db/migrations/2.5.132.js @@ -0,0 +1,13 @@ +exports.up = async knex => { + await knex.schema + .alterTable('pages', table => { + table.text('icon').notNullable().defaultTo('text-box') + }) + + await knex.schema + .alterTable('pageTree', table => { + table.text('icon').notNullable().defaultTo('text-box') + }) +} + +exports.down = knex => { } diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js index 39549595..f8deda94 100644 --- a/server/graph/resolvers/page.js +++ b/server/graph/resolvers/page.js @@ -82,6 +82,7 @@ module.exports = { 'description', 'isPublished', 'orderPriority', + 'icon', 'isPrivate', 'privateNS', 'contentType', @@ -284,35 +285,6 @@ module.exports = { } }).orderBy([{ column: 'isFolder', order: 'desc' }, 'orderPriority']) - // // Ruslan: Custom sorting for "Tree Navigation" for folder "Users" - // const emojiRegex = /^[\u{1F300}-\u{1F6FF}\u{1F900}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u - // const russianRegex = /[\u0400-\u04FF]/ - // - // const userPrefix = 'Users/' - // results.sort((a, b) => { - // if (a.isFolder !== b.isFolder) { - // return b.isFolder - a.isFolder - // } - // - // if (a.path.startsWith(userPrefix) || a.path.startsWith(userPrefix)) { - // // Emoji first - // const aIsEmoji = emojiRegex.test(a.title) - // const bIsEmoji = emojiRegex.test(b.title) - // - // if (aIsEmoji && !bIsEmoji) return -1 - // if (!aIsEmoji && bIsEmoji) return 1 - // - // // Russian second, only by first letter due to title must contain russian + english - // const aIsRussian = russianRegex.test(a.title[0]) - // const bIsRussian = russianRegex.test(b.title[1]) - // - // if (aIsRussian && !bIsRussian) return -1 - // if (!aIsRussian && bIsRussian) return 1 - // } - // - // return a.title.localeCompare(b.title) - // }) - return results.filter(r => { return WIKI.auth.checkAccess(context.req.user, ['read:pages'], { path: r.path, diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql index 5a1db422..a5fc077d 100644 --- a/server/graph/schemas/page.graphql +++ b/server/graph/schemas/page.graphql @@ -285,7 +285,8 @@ type PageListItem { title: String description: String contentType: String! - orderPriority: Int + orderPriority: Int! + icon: String! isPublished: Boolean! isPrivate: Boolean! privateNS: String @@ -298,6 +299,8 @@ type PageTreeItem { id: Int! path: String! depth: Int! + orderPriority: Int! + icon: String! title: String! isPrivate: Boolean! isFolder: Boolean! diff --git a/server/jobs/rebuild-tree.js b/server/jobs/rebuild-tree.js index 9b828e8e..a3cd9cf4 100644 --- a/server/jobs/rebuild-tree.js +++ b/server/jobs/rebuild-tree.js @@ -10,7 +10,7 @@ module.exports = async (pageId) => { await WIKI.configSvc.loadFromDb() await WIKI.configSvc.applyFlags() - const pages = await WIKI.models.pages.query().select('id', 'path', 'localeCode', 'orderPriority', 'title', 'isPrivate', 'privateNS').orderBy(['localeCode', 'path']) + const pages = await WIKI.models.pages.query().select('id', 'path', 'localeCode', 'orderPriority', 'icon', 'title', 'isPrivate', 'privateNS').orderBy(['localeCode', 'path']) let tree = [] let pik = 0 @@ -33,6 +33,7 @@ module.exports = async (pageId) => { tree.push({ id: pik, orderPriority: page.orderPriority, + icon: page.icon, localeCode: page.localeCode, path: currentPath, depth: depth,