diff --git a/server/locales/en.json b/server/locales/en.json index 0fe2135f..e82cfe26 100644 --- a/server/locales/en.json +++ b/server/locales/en.json @@ -1683,6 +1683,25 @@ "history.restore.confirmText": "Are you sure you want to restore this page content as it was on {date}? This version will be copied on top of the current history. As such, newer versions will still be preserved.", "history.restore.confirmTitle": "Restore page version?", "history.restore.success": "Page version restored succesfully!", + "navEdit.editMenuItems": "Edit Menu Items", + "navEdit.header": "Header", + "navEdit.icon": "Icon", + "navEdit.iconHint": "Icon to display to the left of the menu item.", + "navEdit.label": "Label", + "navEdit.labelHint": "Text to display on the menu item.", + "navEdit.link": "Link", + "navEdit.nestItem": "Nest Item", + "navEdit.openInNewWindow": "Open in New Window", + "navEdit.openInNewWindowHint": "Whether the link should open in a new window / tab.", + "navEdit.separator": "Separator", + "navEdit.target": "Target", + "navEdit.targetHint": "Target path or external link to point to.", + "navEdit.title": "Edit Navigation", + "navEdit.unnestItem": "Unnest Item", + "navEdit.visibility": "Visibility", + "navEdit.visibilityAll": "Everyone", + "navEdit.visibilityHint": "Whether to show the menu item to everyone or just selected groups.", + "navEdit.visibilityLimited": "Selected Groups", "pageDeleteDialog.confirm": "Are you sure you want to delete the page {name}?", "pageDeleteDialog.deleteSuccess": "Page deleted successfully.", "pageDeleteDialog.pageId": "Page ID {id}", diff --git a/ux/package-lock.json b/ux/package-lock.json index e932771e..6f6ce671 100644 --- a/ux/package-lock.json +++ b/ux/package-lock.json @@ -84,6 +84,8 @@ "quasar": "2.12.1", "slugify": "1.6.6", "socket.io-client": "4.7.1", + "sortablejs": "1.15.0", + "sortablejs-vue3": "1.2.9", "tabulator-tables": "5.5.0", "tippy.js": "6.3.7", "twemoji": "14.0.2", @@ -6920,8 +6922,26 @@ } }, "node_modules/sortablejs": { - "version": "1.14.0", - "license": "MIT" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", + "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==" + }, + "node_modules/sortablejs-vue3": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/sortablejs-vue3/-/sortablejs-vue3-1.2.9.tgz", + "integrity": "sha512-l0IIBdu+nRIwC2+KOkiavXw5vRfsn6MIPVSVSf7ItBevcuRZ4mVzC7dgnr/Hs/VPH2Q+nF2PYP3FsrnrG+7qCw==", + "dependencies": { + "sortablejs": "^1.15.0", + "vue": "^3.2.37" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/MaxLeiter/" + }, + "peerDependencies": { + "sortablejs": "^1.15.0", + "vue": "^3.2.25" + } }, "node_modules/source-map": { "version": "0.6.1", @@ -7731,6 +7751,11 @@ "vue": "^3.0.1" } }, + "node_modules/vuedraggable/node_modules/sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==" + }, "node_modules/wcwidth": { "version": "1.0.1", "dev": true, diff --git a/ux/public/_assets/icons/fluent-sidebar-menu.svg b/ux/public/_assets/icons/fluent-sidebar-menu.svg new file mode 100644 index 00000000..2b7d00c7 --- /dev/null +++ b/ux/public/_assets/icons/fluent-sidebar-menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/public/_assets/icons/ultraviolet-external-link.svg b/ux/public/_assets/icons/ultraviolet-external-link.svg new file mode 100644 index 00000000..d763104a --- /dev/null +++ b/ux/public/_assets/icons/ultraviolet-external-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/public/_assets/icons/ultraviolet-spring.svg b/ux/public/_assets/icons/ultraviolet-spring.svg new file mode 100644 index 00000000..e8910175 --- /dev/null +++ b/ux/public/_assets/icons/ultraviolet-spring.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/public/_assets/icons/ultraviolet-typography.svg b/ux/public/_assets/icons/ultraviolet-typography.svg new file mode 100644 index 00000000..8c7d423f --- /dev/null +++ b/ux/public/_assets/icons/ultraviolet-typography.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/public/_assets/icons/ultraviolet-user-groups.svg b/ux/public/_assets/icons/ultraviolet-user-groups.svg new file mode 100644 index 00000000..0a87dbcb --- /dev/null +++ b/ux/public/_assets/icons/ultraviolet-user-groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/src/components/MainOverlayDialog.vue b/ux/src/components/MainOverlayDialog.vue index 1b75fff8..2d1d67a0 100644 --- a/ux/src/components/MainOverlayDialog.vue +++ b/ux/src/components/MainOverlayDialog.vue @@ -27,6 +27,10 @@ const overlays = { loader: () => import('./FileManager.vue'), loadingComponent: LoadingGeneric }), + NavEdit: defineAsyncComponent({ + loader: () => import('./NavEditOverlay.vue'), + loadingComponent: LoadingGeneric + }), TableEditor: defineAsyncComponent({ loader: () => import('./TableEditorOverlay.vue'), loadingComponent: LoadingGeneric diff --git a/ux/src/components/NavEditMenu.vue b/ux/src/components/NavEditMenu.vue new file mode 100644 index 00000000..7e2d79b7 --- /dev/null +++ b/ux/src/components/NavEditMenu.vue @@ -0,0 +1,88 @@ + + + diff --git a/ux/src/components/NavEditOverlay.vue b/ux/src/components/NavEditOverlay.vue new file mode 100644 index 00000000..ef013995 --- /dev/null +++ b/ux/src/components/NavEditOverlay.vue @@ -0,0 +1,518 @@ + + + + + diff --git a/ux/src/components/NavSidebar.vue b/ux/src/components/NavSidebar.vue new file mode 100644 index 00000000..d4aef31d --- /dev/null +++ b/ux/src/components/NavSidebar.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/ux/src/css/app.scss b/ux/src/css/app.scss index 6a51c324..b8c55b08 100644 --- a/ux/src/css/app.scss +++ b/ux/src/css/app.scss @@ -36,6 +36,10 @@ body::-webkit-scrollbar-thumb { font-family: 'Roboto Mono', Consolas, "Liberation Mono", Courier, monospace; } +.text-wordbreak-all { + word-break: break-all; +} + // ------------------------------------------------------------------ // THEME COLORS // ------------------------------------------------------------------ diff --git a/ux/src/layouts/MainLayout.vue b/ux/src/layouts/MainLayout.vue index 1a2f1e2e..49c250b7 100644 --- a/ux/src/layouts/MainLayout.vue +++ b/ux/src/layouts/MainLayout.vue @@ -30,40 +30,27 @@ q-layout(view='hHh Lpr lff') aria-label='Browse' size='sm' ) - q-scroll-area.sidebar-nav( - :thumb-style='thumbStyle' - :bar-style='barStyle' - ) - q-list( - clickable - dense - dark - ) - q-item-label.text-blue-2.text-caption(header) Header - q-item(to='/install') - q-item-section(side) - q-icon(name='las la-dog', color='white') - q-item-section Link 1 - q-item(to='/install') - q-item-section(side) - q-icon(name='las la-cat', color='white') - q-item-section Link 2 - q-separator.q-my-sm(dark) - q-item(to='/install') - q-item-section(side) - q-icon(name='mdi-fruit-grapes', color='white') - q-item-section Link 3 - q-bar.bg-blue-9.text-white(dense, v-if='flagsStore.experimental && userStore.authenticated') + nav-sidebar + q-bar.bg-blue-9.text-white(dense, v-if='userStore.authenticated') q-btn.col( icon='las la-dharmachakra' - label='History' + label='Edit Nav' flat - ) + ) + q-menu( + ref='navEditMenu' + anchor='top left' + self='bottom left' + :offset='[0, 10]' + ) + nav-edit-menu(:menu-hide-handler='navEditMenu.hide') + q-separator(vertical) q-btn.col( icon='las la-bookmark' label='Bookmarks' flat + disabled ) q-page-container router-view @@ -99,6 +86,8 @@ import { useUserStore } from 'src/stores/user' import FooterNav from 'src/components/FooterNav.vue' import HeaderNav from 'src/components/HeaderNav.vue' import LocaleSelectorMenu from 'src/components/LocaleSelectorMenu.vue' +import NavSidebar from 'src/components/NavSidebar.vue' +import NavEditMenu from 'src/components/NavEditMenu.vue' import MainOverlayDialog from 'src/components/MainOverlayDialog.vue' // QUASAR @@ -128,23 +117,9 @@ useMeta({ titleTemplate: title => `${title} - ${siteStore.title}` }) -// DATA +// REFS -const leftDrawerOpen = ref(true) -const search = ref('') - -const thumbStyle = { - right: '2px', - borderRadius: '5px', - backgroundColor: '#FFF', - width: '5px', - opacity: 0.5 -} -const barStyle = { - backgroundColor: '#000', - width: '9px', - opacity: 0.1 -} +const navEditMenu = ref(null) // COMPUTED @@ -152,12 +127,6 @@ const isSidebarShown = computed(() => { return siteStore.showSideNav && !siteStore.sideNavIsDisabled && !(editorStore.isActive && editorStore.hideSideNav) }) -// METHODS - -function openFileManager () { - siteStore.openFileManager() -} -