Unverified Commit d2a18eca authored by NGPixel's avatar NGPixel

feat: welcome overlay + editor improvements

parent b979e508
...@@ -9,6 +9,8 @@ git config oh-my-zsh.hide-info 1 ...@@ -9,6 +9,8 @@ git config oh-my-zsh.hide-info 1
echo "Waiting for DB container to come online..." echo "Waiting for DB container to come online..."
/usr/local/bin/wait-for localhost:5432 -- echo "DB ready" /usr/local/bin/wait-for localhost:5432 -- echo "DB ready"
npm install -g npm-check-updates
echo "Installing dependencies..." echo "Installing dependencies..."
cd server cd server
npm install npm install
......
...@@ -13,5 +13,9 @@ ...@@ -13,5 +13,9 @@
"i18n-ally.localesPaths": [ "i18n-ally.localesPaths": [
"ux/src/i18n/locales" "ux/src/i18n/locales"
], ],
"i18n-ally.keystyle": "flat" "i18n-ally.keystyle": "flat",
"i18n-ally.sortKeys": true,
"i18n-ally.enabledFrameworks": [
"vue"
]
} }
...@@ -198,7 +198,7 @@ ...@@ -198,7 +198,7 @@
}, },
"ext": "js,json,graphql,gql", "ext": "js,json,graphql,gql",
"watch": [ "watch": [
"./" "server"
] ]
} }
} }
...@@ -11,41 +11,42 @@ ...@@ -11,41 +11,42 @@
"lint": "eslint --ext .js,.vue ./" "lint": "eslint --ext .js,.vue ./"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "3.7.7", "@apollo/client": "3.7.11",
"@lezer/common": "1.0.2", "@lezer/common": "1.0.2",
"@quasar/extras": "1.15.10", "@mdi/font": "7.2.96",
"@tiptap/core": "2.0.0-beta.212", "@quasar/extras": "1.16.1",
"@tiptap/extension-code-block": "2.0.0-beta.212", "@tiptap/core": "2.0.1",
"@tiptap/extension-code-block-lowlight": "2.0.0-beta.212", "@tiptap/extension-code-block": "2.0.1",
"@tiptap/extension-color": "2.0.0-beta.212", "@tiptap/extension-code-block-lowlight": "2.0.1",
"@tiptap/extension-dropcursor": "2.0.0-beta.212", "@tiptap/extension-color": "2.0.1",
"@tiptap/extension-font-family": "2.0.0-beta.212", "@tiptap/extension-dropcursor": "2.0.1",
"@tiptap/extension-gapcursor": "2.0.0-beta.212", "@tiptap/extension-font-family": "2.0.1",
"@tiptap/extension-hard-break": "2.0.0-beta.212", "@tiptap/extension-gapcursor": "2.0.1",
"@tiptap/extension-highlight": "2.0.0-beta.212", "@tiptap/extension-hard-break": "2.0.1",
"@tiptap/extension-history": "2.0.0-beta.212", "@tiptap/extension-highlight": "2.0.1",
"@tiptap/extension-image": "2.0.0-beta.212", "@tiptap/extension-history": "2.0.1",
"@tiptap/extension-mention": "2.0.0-beta.212", "@tiptap/extension-image": "2.0.1",
"@tiptap/extension-placeholder": "2.0.0-beta.212", "@tiptap/extension-mention": "2.0.1",
"@tiptap/extension-table": "2.0.0-beta.212", "@tiptap/extension-placeholder": "2.0.1",
"@tiptap/extension-table-cell": "2.0.0-beta.212", "@tiptap/extension-table": "2.0.1",
"@tiptap/extension-table-header": "2.0.0-beta.212", "@tiptap/extension-table-cell": "2.0.1",
"@tiptap/extension-table-row": "2.0.0-beta.212", "@tiptap/extension-table-header": "2.0.1",
"@tiptap/extension-task-item": "2.0.0-beta.212", "@tiptap/extension-table-row": "2.0.1",
"@tiptap/extension-task-list": "2.0.0-beta.212", "@tiptap/extension-task-item": "2.0.1",
"@tiptap/extension-text-align": "2.0.0-beta.212", "@tiptap/extension-task-list": "2.0.1",
"@tiptap/extension-text-style": "2.0.0-beta.212", "@tiptap/extension-text-align": "2.0.1",
"@tiptap/extension-typography": "2.0.0-beta.212", "@tiptap/extension-text-style": "2.0.1",
"@tiptap/pm": "2.0.0-beta.212", "@tiptap/extension-typography": "2.0.1",
"@tiptap/starter-kit": "2.0.0-beta.212", "@tiptap/pm": "2.0.1",
"@tiptap/vue-3": "2.0.0-beta.212", "@tiptap/starter-kit": "2.0.1",
"@tiptap/vue-3": "2.0.1",
"apollo-upload-client": "17.0.0", "apollo-upload-client": "17.0.0",
"browser-fs-access": "0.31.2", "browser-fs-access": "0.33.0",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"codemirror": "5.65.11", "codemirror": "5.65.11",
"codemirror-asciidoc": "1.0.4", "codemirror-asciidoc": "1.0.4",
"dependency-graph": "0.11.0", "dependency-graph": "0.11.0",
"filesize": "10.0.6", "filesize": "10.0.7",
"filesize-parser": "1.5.0", "filesize-parser": "1.5.0",
"fuse.js": "6.6.2", "fuse.js": "6.6.2",
"graphql": "16.6.0", "graphql": "16.6.0",
...@@ -54,45 +55,45 @@ ...@@ -54,45 +55,45 @@
"jwt-decode": "3.1.2", "jwt-decode": "3.1.2",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"lowlight": "2.8.1", "lowlight": "2.8.1",
"luxon": "3.2.1", "luxon": "3.3.0",
"pinia": "2.0.30", "pinia": "2.0.33",
"prosemirror-commands": "1.5.0", "prosemirror-commands": "1.5.1",
"prosemirror-history": "1.3.0", "prosemirror-history": "1.3.0",
"prosemirror-keymap": "1.2.0", "prosemirror-keymap": "1.2.1",
"prosemirror-model": "1.19.0", "prosemirror-model": "1.19.0",
"prosemirror-schema-list": "1.2.2", "prosemirror-schema-list": "1.2.2",
"prosemirror-state": "1.4.2", "prosemirror-state": "1.4.2",
"prosemirror-transform": "1.7.1", "prosemirror-transform": "1.7.1",
"prosemirror-view": "1.30.1", "prosemirror-view": "1.30.2",
"pug": "3.0.2", "pug": "3.0.2",
"quasar": "2.11.5", "quasar": "2.11.9",
"slugify": "1.6.5", "slugify": "1.6.6",
"socket.io-client": "4.5.4", "socket.io-client": "4.6.1",
"tabulator-tables": "5.4.4", "tabulator-tables": "5.4.4",
"tippy.js": "6.3.7", "tippy.js": "6.3.7",
"uuid": "9.0.0", "uuid": "9.0.0",
"v-network-graph": "0.8.1", "v-network-graph": "0.9.1",
"vue": "3.2.47", "vue": "3.2.47",
"vue-i18n": "9.2.2", "vue-i18n": "9.2.2",
"vue-router": "4.1.6", "vue-router": "4.1.6",
"vue3-otp-input": "0.3.6", "vue3-otp-input": "0.4.1",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"xterm": "5.1.0", "xterm": "5.1.0",
"zxcvbn": "4.4.2" "zxcvbn": "4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@intlify/unplugin-vue-i18n": "0.8.1", "@intlify/unplugin-vue-i18n": "0.10.0",
"@quasar/app-vite": "1.2.0", "@quasar/app-vite": "1.2.1",
"@types/lodash": "4.14.191", "@types/lodash": "4.14.192",
"@volar/vue-language-plugin-pug": "1.0.24", "@volar/vue-language-plugin-pug": "1.2.0",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.14",
"browserlist": "latest", "browserlist": "latest",
"eslint": "8.33.0", "eslint": "8.37.0",
"eslint-config-standard": "17.0.0", "eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
"eslint-plugin-n": "15.6.1", "eslint-plugin-n": "15.7.0",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-vue": "9.9.0" "eslint-plugin-vue": "9.10.0"
}, },
"engines": { "engines": {
"node": ">= 18.0", "node": ">= 18.0",
......
...@@ -50,7 +50,7 @@ module.exports = configure(function (/* ctx */) { ...@@ -50,7 +50,7 @@ module.exports = configure(function (/* ctx */) {
extras: [ extras: [
// 'ionicons-v4', // 'ionicons-v4',
// 'mdi-v5', // 'mdi-v5',
'mdi-v7', // 'mdi-v7',
// 'fontawesome-v6', // 'fontawesome-v6',
// 'eva-icons', // 'eva-icons',
// 'themify', // 'themify',
......
...@@ -10,6 +10,8 @@ import { useSiteStore } from 'src/stores/site' ...@@ -10,6 +10,8 @@ import { useSiteStore } from 'src/stores/site'
import { useUserStore } from 'src/stores/user' import { useUserStore } from 'src/stores/user'
import { setCssVar, useQuasar } from 'quasar' import { setCssVar, useQuasar } from 'quasar'
import '@mdi/font/css/materialdesignicons.css'
/* global siteConfig */ /* global siteConfig */
// QUASAR // QUASAR
......
...@@ -26,6 +26,10 @@ const overlays = { ...@@ -26,6 +26,10 @@ const overlays = {
TableEditor: defineAsyncComponent({ TableEditor: defineAsyncComponent({
loader: () => import('./TableEditorOverlay.vue'), loader: () => import('./TableEditorOverlay.vue'),
loadingComponent: LoadingGeneric loadingComponent: LoadingGeneric
}),
Welcome: defineAsyncComponent({
loader: () => import('./WelcomeOverlay.vue'),
loadingComponent: LoadingGeneric
}) })
} }
......
<template lang="pug">
.page-actions.column.items-stretch.order-last(:class='editorStore.isActive ? `is-editor` : ``')
q-btn.q-py-md(
flat
icon='las la-pen-nib'
:color='editorStore.isActive ? `white` : `deep-orange-9`'
aria-label='Page Properties'
@click='togglePageProperties'
)
q-tooltip(anchor='center left' self='center right') Page Properties
q-btn.q-py-md(
flat
icon='las la-project-diagram'
:color='editorStore.isActive ? `white` : `deep-orange-9`'
aria-label='Page Data'
@click='togglePageData'
disable
v-if='flagsStore.experimental'
)
q-tooltip(anchor='center left' self='center right') Page Data
template(v-if='!(editorStore.isActive && editorStore.mode === `create`)')
q-separator.q-my-sm(inset)
q-btn.q-py-sm(
flat
icon='las la-ellipsis-h'
:color='editorStore.isActive ? `deep-orange-2` : `grey`'
aria-label='Page Actions'
)
q-tooltip(anchor='center left' self='center right') Page Actions
q-menu(
anchor='top left'
self='top right'
auto-close
transition-show='jump-left'
)
q-list(padding, style='min-width: 225px;')
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-history', size='sm')
q-item-section
q-item-label View History
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-code', size='sm')
q-item-section
q-item-label View Source
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-atom', size='sm')
q-item-section
q-item-label Convert Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-magic', size='sm')
q-item-section
q-item-label Re-render Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-sun', size='sm')
q-item-section
q-item-label View Backlinks
q-space
template(v-if='!(editorStore.isActive && editorStore.mode === `create`)')
q-btn.q-py-sm(
flat
icon='las la-copy'
:color='editorStore.isActive ? `deep-orange-2` : `grey`'
aria-label='Duplicate Page'
@click='duplicatePage'
)
q-tooltip(anchor='center left' self='center right') Duplicate Page
q-btn.q-py-sm(
flat
icon='las la-share'
:color='editorStore.isActive ? `deep-orange-2` : `grey`'
aria-label='Rename / Move Page'
@click='renamePage'
)
q-tooltip(anchor='center left' self='center right') Rename / Move Page
q-btn.q-py-sm(
flat
icon='las la-trash'
:color='editorStore.isActive ? `deep-orange-2` : `grey`'
aria-label='Delete Page'
@click='deletePage'
:class='editorStore.isActive ? `q-pb-md` : ``'
)
q-tooltip(anchor='center left' self='center right') Delete Page
span.page-actions-mode(v-else) {{ t('common.actions.newPage') }}
</template>
<script setup>
import { useQuasar } from 'quasar'
import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useEditorStore } from 'src/stores/editor'
import { useFlagsStore } from 'src/stores/flags'
import { usePageStore } from 'src/stores/page'
import { useSiteStore } from 'src/stores/site'
// QUASAR
const $q = useQuasar()
// STORES
const editorStore = useEditorStore()
const flagsStore = useFlagsStore()
const pageStore = usePageStore()
const siteStore = useSiteStore()
// ROUTER
const router = useRouter()
const route = useRoute()
// I18N
const { t } = useI18n()
// METHODS
function togglePageProperties () {
siteStore.$patch({
sideDialogComponent: 'PagePropertiesDialog',
sideDialogShown: true
})
}
function togglePageData () {
siteStore.$patch({
sideDialogComponent: 'PageDataDialog',
sideDialogShown: true
})
}
function duplicatePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/TreeBrowserDialog.vue')),
componentProps: {
mode: 'duplicatePage',
folderPath: '',
itemId: pageStore.id,
itemTitle: pageStore.title,
itemFileName: pageStore.path
}
}).onOk(() => {
// TODO: change route to new location
})
}
function renamePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/TreeBrowserDialog.vue')),
componentProps: {
mode: 'renamePage',
folderPath: '',
itemId: pageStore.id,
itemTitle: pageStore.title,
itemFileName: pageStore.path
}
}).onOk(() => {
// TODO: change route to new location
})
}
function deletePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/PageDeleteDialog.vue')),
componentProps: {
pageId: pageStore.id,
pageName: pageStore.title
}
}).onOk(() => {
router.replace('/')
})
}
</script>
<style lang="scss">
.page-actions {
flex: 0 0 56px;
@at-root .body--light & {
background-color: $grey-3;
}
@at-root .body--dark & {
background-color: $dark-4;
}
&.is-editor {
@at-root .body--light & {
background-color: $deep-orange-9;
}
@at-root .body--dark & {
background-color: $deep-orange-9;
}
}
&-mode {
writing-mode: vertical-rl;
text-orientation: mixed;
padding: 1.75rem 1rem 1.75rem 0;
color: $deep-orange-3;
font-weight: 500;
}
}
</style>
<template lang="pug">
q-dialog(
v-model='siteStore.sideDialogShown'
position='right'
full-height
transition-show='jump-left'
transition-hide='jump-right'
class='floating-sidepanel'
no-shake
)
component(:is='sideDialogs[siteStore.sideDialogComponent]')
</template>
<script setup>
import { useQuasar } from 'quasar'
import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useEditorStore } from 'src/stores/editor'
import { useFlagsStore } from 'src/stores/flags'
import { usePageStore } from 'src/stores/page'
import { useSiteStore } from 'src/stores/site'
// COMPONENTS
import LoadingGeneric from 'src/components/LoadingGeneric.vue'
const sideDialogs = {
PageDataDialog: defineAsyncComponent({
loader: () => import('src/components/PageDataDialog.vue'),
loadingComponent: LoadingGeneric
}),
PagePropertiesDialog: defineAsyncComponent({
loader: () => import('src/components/PagePropertiesDialog.vue'),
loadingComponent: LoadingGeneric
})
}
// QUASAR
const $q = useQuasar()
// STORES
const editorStore = useEditorStore()
const flagsStore = useFlagsStore()
const pageStore = usePageStore()
const siteStore = useSiteStore()
// ROUTER
const router = useRouter()
const route = useRoute()
// I18N
const { t } = useI18n()
// DATA
const state = reactive({
showSideDialog: false,
sideDialogComponent: null,
showGlobalDialog: false,
globalDialogComponent: null,
showTagsEditBtn: false,
tagEditMode: false,
tocExpanded: ['h1-0', 'h1-1'],
tocSelected: [],
currentRating: 3
})
</script>
<style lang="scss">
.floating-sidepanel {
.q-dialog__inner {
right: 24px;
.q-card {
border-radius: 4px !important;
min-width: 450px;
.q-card__section {
border-radius: 0;
}
}
}
.alt-card {
@at-root .body--light & {
background-color: $grey-2;
border-top: 1px solid $grey-4;
box-shadow: inset 0 1px 0 0 #FFF, inset 0 -1px 0 0 #FFF;
border-bottom: 1px solid $grey-4;
}
@at-root .body--dark & {
background-color: $dark-4;
border-top: 1px solid lighten($dark-3, 8%);
box-shadow: inset 0 1px 0 0 $dark-6, inset 0 -1px 0 0 $dark-6;
border-bottom: 1px solid lighten($dark-3, 8%);
}
}
&-quickaccess {
width: 40px;
border-radius: 4px !important;
background-color: rgba(0,0,0,.75);
backdrop-filter: blur(5px);
color: #FFF;
position: fixed;
right: 486px;
top: 74px;
z-index: -1;
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 rgba(0,0,0,.5) !important;
@at-root .q-transition--jump-left-enter-active & {
display: none !important;
}
@at-root .q-transition--jump-right-leave-active & {
display: none !important;
}
}
}
</style>
...@@ -13,22 +13,68 @@ ...@@ -13,22 +13,68 @@
:label='t(`welcome.createHome`)' :label='t(`welcome.createHome`)'
icon='las la-plus' icon='las la-plus'
no-caps no-caps
href='/_edit'
) )
q-menu.translucent-menu(
auto-close
anchor='top left'
self='bottom left'
)
q-list(padding)
q-item(
clickable
@click='createHomePage(`wysiwyg`)'
v-if='siteStore.editors.wysiwyg'
)
blueprint-icon(icon='google-presentation')
q-item-section.q-pr-sm Using the Visual Editor
q-item-section(side): q-icon(name='mdi-chevron-right')
q-item(
clickable
@click='createHomePage(`markdown`)'
v-if='siteStore.editors.markdown'
)
blueprint-icon(icon='markdown')
q-item-section.q-pr-sm Using the Markdown Editor
q-item-section(side): q-icon(name='mdi-chevron-right')
q-item(
clickable
@click='createHomePage(`asciidoc`)'
v-if='siteStore.editors.asciidoc'
)
blueprint-icon(icon='asciidoc')
q-item-section.q-pr-sm Using the AsciiDoc Editor
q-item-section(side): q-icon(name='mdi-chevron-right')
q-btn( q-btn(
push push
color='primary' color='primary'
:label='t(`welcome.admin`)' :label='t(`welcome.admin`)'
icon='las la-cog' icon='las la-cog'
no-caps no-caps
to='/_admin' @click='loadAdmin'
) )
</template> </template>
<script setup> <script setup>
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useMeta } from 'quasar' import { useRouter } from 'vue-router'
import { useMeta, useQuasar } from 'quasar'
import { useSiteStore } from 'src/stores/site'
import { usePageStore } from 'src/stores/page'
// QUASAR
const $q = useQuasar()
// STORES
const pageStore = usePageStore()
const siteStore = useSiteStore()
// ROUTER
const router = useRouter()
// I18N // I18N
...@@ -40,13 +86,27 @@ useMeta({ ...@@ -40,13 +86,27 @@ useMeta({
title: t('welcome.title') title: t('welcome.title')
}) })
// METHODS
function createHomePage (editor) {
siteStore.overlay = ''
pageStore.pageCreate({ editor, locale: 'en', path: '' })
}
function loadAdmin () {
siteStore.overlay = ''
router.push('/_admin')
}
</script> </script>
<style lang="scss"> <style lang="scss">
.welcome { .welcome {
background: $dark-6 radial-gradient(ellipse, $dark-4, $dark-6); background: #FFF radial-gradient(ellipse, #FFF, #DDD);
color: #FFF; color: $grey-9;
height: 100vh; height: 100vh;
border: 10px solid #EEE;
border-radius: 25px !important;
&-bg { &-bg {
position: absolute; position: absolute;
...@@ -54,10 +114,10 @@ useMeta({ ...@@ -54,10 +114,10 @@ useMeta({
left: 50%; left: 50%;
width: 320px; width: 320px;
height: 320px; height: 320px;
background: linear-gradient(0, $purple-6 50%, $blue-9 50%); background: linear-gradient(0, #FFF 50%, $blue-5 50%);
border-radius: 50%; border-radius: 50%;
filter: blur(80px); filter: blur(100px);
transform: translate(-50%, -50%); transform: translate(-50%, -55%);
} }
&-content { &-content {
...@@ -96,7 +156,7 @@ useMeta({ ...@@ -96,7 +156,7 @@ useMeta({
&-subtitle { &-subtitle {
font-size: 1.2rem; font-size: 1.2rem;
font-weight: 500; font-weight: 500;
color: $purple-2; color: $blue-7;
line-height: 1.2rem; line-height: 1.2rem;
margin-top: 1rem; margin-top: 1rem;
} }
......
...@@ -202,6 +202,7 @@ body::-webkit-scrollbar-thumb { ...@@ -202,6 +202,7 @@ body::-webkit-scrollbar-thumb {
@at-root .body--dark & { @at-root .body--dark & {
background-color: rgba($dark,.7); background-color: rgba($dark,.7);
} }
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
> .q-card { > .q-card {
......
...@@ -149,105 +149,13 @@ q-page.column ...@@ -149,105 +149,13 @@ q-page.column
icon='las la-thumbs-up' icon='las la-thumbs-up'
color='secondary' color='secondary'
) )
.page-actions.column.items-stretch.order-last page-actions-col
q-btn.q-py-md(
flat side-dialog
icon='las la-pen-nib'
color='deep-orange-9'
aria-label='Page Properties'
@click='togglePageProperties'
)
q-tooltip(anchor='center left' self='center right') Page Properties
q-btn.q-py-md(
flat
icon='las la-project-diagram'
color='deep-orange-9'
aria-label='Page Data'
@click='togglePageData'
disable
v-if='flagsStore.experimental'
)
q-tooltip(anchor='center left' self='center right') Page Data
q-separator.q-my-sm(inset)
q-btn.q-py-sm(
flat
icon='las la-ellipsis-h'
color='grey'
aria-label='Page Actions'
)
q-tooltip(anchor='center left' self='center right') Page Actions
q-menu(
anchor='top left'
self='top right'
auto-close
transition-show='jump-left'
)
q-list(padding, style='min-width: 225px;')
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-history', size='sm')
q-item-section
q-item-label View History
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-code', size='sm')
q-item-section
q-item-label View Source
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-atom', size='sm')
q-item-section
q-item-label Convert Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-magic', size='sm')
q-item-section
q-item-label Re-render Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-sun', size='sm')
q-item-section
q-item-label View Backlinks
q-space
q-btn.q-py-sm(
flat
icon='las la-copy'
color='grey'
aria-label='Duplicate Page'
@click='duplicatePage'
)
q-tooltip(anchor='center left' self='center right') Duplicate Page
q-btn.q-py-sm(
flat
icon='las la-share'
color='grey'
aria-label='Rename / Move Page'
@click='renamePage'
)
q-tooltip(anchor='center left' self='center right') Rename / Move Page
q-btn.q-py-sm(
flat
icon='las la-trash'
color='grey'
aria-label='Delete Page'
@click='deletePage'
)
q-tooltip(anchor='center left' self='center right') Delete Page
q-dialog(
v-model='state.showSideDialog'
position='right'
full-height
transition-show='jump-left'
transition-hide='jump-right'
class='floating-sidepanel'
no-shake
)
component(:is='sideDialogs[state.sideDialogComponent]')
</template> </template>
<script setup> <script setup>
import { useMeta, useQuasar, setCssVar } from 'quasar' import { useMeta, useQuasar } from 'quasar'
import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue' import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
...@@ -261,19 +169,10 @@ import { useSiteStore } from 'src/stores/site' ...@@ -261,19 +169,10 @@ import { useSiteStore } from 'src/stores/site'
// COMPONENTS // COMPONENTS
import LoadingGeneric from 'src/components/LoadingGeneric.vue' import LoadingGeneric from 'src/components/LoadingGeneric.vue'
import PageActionsCol from 'src/components/PageActionsCol.vue'
import PageHeader from 'src/components/PageHeader.vue' import PageHeader from 'src/components/PageHeader.vue'
import PageTags from '../components/PageTags.vue' import PageTags from 'src/components/PageTags.vue'
import SideDialog from 'src/components/SideDialog.vue'
const sideDialogs = {
PageDataDialog: defineAsyncComponent({
loader: () => import('../components/PageDataDialog.vue'),
loadingComponent: LoadingGeneric
}),
PagePropertiesDialog: defineAsyncComponent({
loader: () => import('../components/PagePropertiesDialog.vue'),
loadingComponent: LoadingGeneric
})
}
const editorComponents = { const editorComponents = {
markdown: defineAsyncComponent({ markdown: defineAsyncComponent({
...@@ -364,10 +263,14 @@ watch(() => route.path, async (newValue) => { ...@@ -364,10 +263,14 @@ watch(() => route.path, async (newValue) => {
await pageStore.pageLoad({ path: newValue }) await pageStore.pageLoad({ path: newValue })
} catch (err) { } catch (err) {
if (err.message === 'ERR_PAGE_NOT_FOUND') { if (err.message === 'ERR_PAGE_NOT_FOUND') {
if (newValue === '/') {
siteStore.overlay = 'Welcome'
} else {
$q.notify({ $q.notify({
type: 'negative', type: 'negative',
message: 'This page does not exist (yet)!' message: 'This page does not exist (yet)!'
}) })
}
} else { } else {
$q.notify({ $q.notify({
type: 'negative', type: 'negative',
...@@ -382,58 +285,6 @@ watch(() => pageStore.tocDepth, () => { refreshTocExpanded() }) ...@@ -382,58 +285,6 @@ watch(() => pageStore.tocDepth, () => { refreshTocExpanded() })
// METHODS // METHODS
function togglePageProperties () {
state.sideDialogComponent = 'PagePropertiesDialog'
state.showSideDialog = true
}
function togglePageData () {
state.sideDialogComponent = 'PageDataDialog'
state.showSideDialog = true
}
function duplicatePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/TreeBrowserDialog.vue')),
componentProps: {
mode: 'duplicatePage',
folderPath: '',
itemId: pageStore.id,
itemTitle: pageStore.title,
itemFileName: pageStore.path
}
}).onOk(() => {
// TODO: change route to new location
})
}
function renamePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/TreeBrowserDialog.vue')),
componentProps: {
mode: 'renamePage',
folderPath: '',
itemId: pageStore.id,
itemTitle: pageStore.title,
itemFileName: pageStore.path
}
}).onOk(() => {
// TODO: change route to new location
})
}
function deletePage () {
$q.dialog({
component: defineAsyncComponent(() => import('../components/PageDeleteDialog.vue')),
componentProps: {
pageId: pageStore.id,
pageName: pageStore.title
}
}).onOk(() => {
router.replace('/')
})
}
function refreshTocExpanded (baseToc, lvl) { function refreshTocExpanded (baseToc, lvl) {
const toExpand = [] const toExpand = []
let isRootNode = false let isRootNode = false
...@@ -538,16 +389,6 @@ function refreshTocExpanded (baseToc, lvl) { ...@@ -538,16 +389,6 @@ function refreshTocExpanded (baseToc, lvl) {
} }
} }
} }
.page-actions {
flex: 0 0 56px;
@at-root .body--light & {
background-color: $grey-3;
}
@at-root .body--dark & {
background-color: $dark-4;
}
}
.floating-syncpanel { .floating-syncpanel {
.q-dialog__inner { .q-dialog__inner {
...@@ -570,59 +411,6 @@ function refreshTocExpanded (baseToc, lvl) { ...@@ -570,59 +411,6 @@ function refreshTocExpanded (baseToc, lvl) {
} }
} }
.floating-sidepanel {
.q-dialog__inner {
right: 24px;
.q-card {
border-radius: 4px !important;
min-width: 450px;
.q-card__section {
border-radius: 0;
}
}
}
.alt-card {
@at-root .body--light & {
background-color: $grey-2;
border-top: 1px solid $grey-4;
box-shadow: inset 0 1px 0 0 #FFF, inset 0 -1px 0 0 #FFF;
border-bottom: 1px solid $grey-4;
}
@at-root .body--dark & {
background-color: $dark-4;
border-top: 1px solid lighten($dark-3, 8%);
box-shadow: inset 0 1px 0 0 $dark-6, inset 0 -1px 0 0 $dark-6;
border-bottom: 1px solid lighten($dark-3, 8%);
}
}
&-quickaccess {
width: 40px;
border-radius: 4px !important;
background-color: rgba(0,0,0,.75);
backdrop-filter: blur(5px);
color: #FFF;
position: fixed;
right: 486px;
top: 74px;
z-index: -1;
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 rgba(0,0,0,.5) !important;
@at-root .q-transition--jump-left-enter-active & {
display: none !important;
}
@at-root .q-transition--jump-right-leave-active & {
display: none !important;
}
}
}
.q-card { .q-card {
@at-root .body--light & { @at-root .body--light & {
background-color: #FFF; background-color: #FFF;
......
...@@ -4,8 +4,8 @@ const routes = [ ...@@ -4,8 +4,8 @@ const routes = [
path: '/', path: '/',
component: () => import('../layouts/MainLayout.vue'), component: () => import('../layouts/MainLayout.vue'),
children: [ children: [
{ path: '', component: () => import('../pages/Index.vue') } { path: '', component: () => import('../pages/Index.vue') },
// { path: 'n/:editor?', component: () => import('../pages/Index.vue') } { path: '_create/:editor?', component: () => import('../pages/Index.vue') }
] ]
}, },
{ {
...@@ -62,10 +62,6 @@ const routes = [ ...@@ -62,10 +62,6 @@ const routes = [
] ]
}, },
{ {
path: '/_welcome',
component: () => import('pages/Welcome.vue')
},
{
path: '/_error/:action?', path: '/_error/:action?',
component: () => import('pages/ErrorGeneric.vue') component: () => import('pages/ErrorGeneric.vue')
}, },
......
...@@ -191,7 +191,7 @@ export const usePageStore = defineStore('page', { ...@@ -191,7 +191,7 @@ export const usePageStore = defineStore('page', {
// -> Page Data // -> Page Data
this.id = 0 this.id = 0
this.locale = locale || this.locale this.locale = locale || this.locale
if (path) { if (path || path === '') {
this.path = path this.path = path
} else { } else {
this.path = this.path.length < 2 ? 'new-page' : `${this.path}/new-page` this.path = this.path.length < 2 ? 'new-page' : `${this.path}/new-page`
...@@ -199,7 +199,7 @@ export const usePageStore = defineStore('page', { ...@@ -199,7 +199,7 @@ export const usePageStore = defineStore('page', {
this.title = '' this.title = ''
this.description = '' this.description = ''
this.icon = 'las la-file-alt' this.icon = 'las la-file-alt'
this.isPublished = false this.publishState = 'published'
this.relations = [] this.relations = []
this.tags = [] this.tags = []
......
...@@ -60,6 +60,8 @@ export const useSiteStore = defineStore('site', { ...@@ -60,6 +60,8 @@ export const useSiteStore = defineStore('site', {
width: '9px', width: '9px',
opacity: 1 opacity: 1
}, },
sideDialogShown: false,
sideDialogComponent: '',
docsBase: 'https://next.js.wiki/docs' docsBase: 'https://next.js.wiki/docs'
}), }),
getters: { getters: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment