Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
7508d92f
You need to sign in or sign up before continuing.
Commit
7508d92f
authored
May 10, 2020
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: redirect editor UI (wip)
parent
85a5af6f
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
320 additions
and
79 deletions
+320
-79
page-selector.vue
client/components/common/page-selector.vue
+28
-9
editor.vue
client/components/editor.vue
+2
-2
editor-modal-blocks.vue
client/components/editor/editor-modal-blocks.vue
+28
-38
editor-modal-editorselect.vue
client/components/editor/editor-modal-editorselect.vue
+30
-30
editor-redirect.vue
client/components/editor/editor-redirect.vue
+224
-0
icon-route.svg
client/static/svg/icon-route.svg
+2
-0
definition.yml
server/modules/editor/redirect/definition.yml
+6
-0
No files found.
client/components/common/page-selector.vue
View file @
7508d92f
...
...
@@ -20,7 +20,7 @@
v-show='searchLoading'
)
.d-flex
v-flex.grey(xs5, :class='
darkMode
? `darken-4` : `lighten-3`')
v-flex.grey(xs5, :class='
$vuetify.theme.dark
? `darken-4` : `lighten-3`')
v-toolbar(color='grey darken-3', dark, dense, flat)
.body-2 Virtual Folders
v-spacer
...
...
@@ -57,7 +57,7 @@
color='primary'
)
template(v-for='(page, idx) of currentPages')
v-list-item(:key='`page-` + page.id', :value='page
.path
')
v-list-item(:key='`page-` + page.id', :value='page')
v-list-item-icon: v-icon mdi-text-box
v-list-item-title
{{
page
.
title
}}
v-divider(v-if='idx < pages.length - 1')
...
...
@@ -69,7 +69,7 @@
icon='mdi-alert'
)
.body-2 This folder is empty.
v-card-actions.grey.pa-2(:class='
darkMode ? `darken-2` : `lighten-1`
')
v-card-actions.grey.pa-2(:class='
$vuetify.theme.dark ? `darken-2` : `lighten-1`', v-if='!mustExist
')
v-select(
solo
dark
...
...
@@ -101,8 +101,7 @@
<
script
>
import
_
from
'lodash'
import
{
get
}
from
'vuex-pathify'
import
pageTreeQuery
from
'gql/common/common-pages-query-tree.gql'
import
gql
from
'graphql-tag'
const
localeSegmentRegex
=
/^
[
A-Z
]{2}(
-
[
A-Z
]{2})?
$/i
...
...
@@ -129,6 +128,10 @@ export default {
openHandler
:
{
type
:
Function
,
default
:
()
=>
{}
},
mustExist
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
...
...
@@ -172,7 +175,6 @@ export default {
}
},
computed
:
{
darkMode
:
get
(
'site/dark'
),
isShown
:
{
get
()
{
return
this
.
value
},
set
(
val
)
{
this
.
$emit
(
'input'
,
val
)
}
...
...
@@ -184,6 +186,9 @@ export default {
if
(
!
this
.
currentPath
)
{
return
false
}
if
(
this
.
mustExist
&&
!
this
.
currentPage
)
{
return
false
}
const
firstSection
=
_
.
head
(
this
.
currentPath
.
split
(
'/'
))
if
(
firstSection
.
length
<=
1
)
{
return
false
...
...
@@ -235,7 +240,7 @@ export default {
},
currentPage
(
newValue
,
oldValue
)
{
if
(
!
_
.
isEmpty
(
newValue
))
{
this
.
currentPath
=
newValue
this
.
currentPath
=
newValue
.
path
}
},
currentLocale
(
newValue
,
oldValue
)
{
...
...
@@ -262,7 +267,8 @@ export default {
open
()
{
const
exit
=
this
.
openHandler
({
locale
:
this
.
currentLocale
,
path
:
this
.
currentPath
path
:
this
.
currentPath
,
id
:
(
this
.
mustExist
&&
this
.
currentPage
)
?
this
.
currentPage
.
pageId
:
0
})
if
(
exit
!==
false
)
{
this
.
close
()
...
...
@@ -271,7 +277,20 @@ export default {
async
fetchFolders
(
item
)
{
this
.
searchLoading
=
true
const
resp
=
await
this
.
$apollo
.
query
({
query
:
pageTreeQuery
,
query
:
gql
`
query ($parent: Int!, $mode: PageTreeMode!, $locale: String!) {
pages {
tree(parent: $parent, mode: $mode, locale: $locale) {
id
path
title
isFolder
pageId
parent
}
}
}
`
,
fetchPolicy
:
'network-only'
,
variables
:
{
parent
:
item
.
id
,
...
...
client/components/editor.vue
View file @
7508d92f
<
template
lang=
"pug"
>
v-app.editor(:dark='
darkMode
')
v-app.editor(:dark='
$vuetify.theme.dark
')
nav-header(dense)
template(slot='mid')
v-text-field.editor-title-input(
...
...
@@ -81,6 +81,7 @@ export default {
editorCode
:
()
=>
import
(
/* webpackChunkName: "editor-code", webpackMode: "lazy" */
'./editor/editor-code.vue'
),
editorCkeditor
:
()
=>
import
(
/* webpackChunkName: "editor-ckeditor", webpackMode: "lazy" */
'./editor/editor-ckeditor.vue'
),
editorMarkdown
:
()
=>
import
(
/* webpackChunkName: "editor-markdown", webpackMode: "lazy" */
'./editor/editor-markdown.vue'
),
editorRedirect
:
()
=>
import
(
/* webpackChunkName: "editor-redirect", webpackMode: "lazy" */
'./editor/editor-redirect.vue'
),
editorModalEditorselect
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-editorselect.vue'
),
editorModalProperties
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-properties.vue'
),
editorModalUnsaved
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-unsaved.vue'
),
...
...
@@ -148,7 +149,6 @@ export default {
},
computed
:
{
currentEditor
:
sync
(
'editor/editor'
),
darkMode
:
get
(
'site/dark'
),
activeModal
:
sync
(
'editor/activeModal'
),
mode
:
get
(
'editor/mode'
),
welcomeMode
()
{
return
this
.
mode
===
`create`
&&
this
.
path
===
`home`
},
...
...
client/components/editor/editor-modal-blocks.vue
View file @
7508d92f
<
template
lang=
'pug'
>
v-card.editor-modal-blocks.animated.fadeInLeft(flat, tile)
v-container.pa-3(grid-list-lg, fluid)
v-layout(row, wrap)
v-flex(xs12, lg4, xl3)
v-card.radius-7(light)
v-row(dense)
v-col(
v-for='(item, idx) of blocks'
:key='`block-` + item.key'
cols='12'
lg='4'
xl='3'
)
v-card.radius-7(light, flat, @click='selectBlock(item)')
v-card-text
.d-flex
v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
.body-2.teal--text Blocks
v-list(two-line)
template(v-for='(item, idx) of blocks')
v-list-item(@click='selectBlock(item)')
v-list-item-avatar
v-avatar.radius-7(color='teal')
v-icon(dark) dashboard
v-list-item-content
v-list-item-title.body-2
{{
item
.
title
}}
v-list-item-sub-title
{{
item
.
description
}}
v-list-item-avatar(v-if='block.key === item.key')
v-icon.animated.fadeInLeft(color='teal') arrow_forward_ios
v-divider(v-if='idx < blocks.length - 1')
v-flex(xs3)
v-card.radius-7.animated.fadeInLeft(light, v-if='block.key')
v-card-text
v-toolbar.radius-7(color='teal lighten-5', dense, flat)
v-icon.mr-3(color='teal') dashboard
.body-2.teal--text
{{
block
.
title
}}
.d-flex.mt-3
v-toolbar.radius-7(flat, color='grey lighten-4', dense, height='44')
.body-2 Coming soon
v-btn.ml-3.my-0.mr-0.radius-7(color='teal', large, @click='', disabled)
v-icon(left) save_alt
span Insert
.d-flex.align-center
v-avatar.radius-7(color='teal')
v-icon(dark)
{{
item
.
icon
}}
.pl-3
.body-2: strong.teal--text
{{
item
.
title
}}
.caption.grey--text
{{
item
.
description
}}
</
template
>
<
script
>
...
...
@@ -49,13 +33,19 @@ export default {
data
()
{
return
{
blocks
:
[
{
key
:
'hero'
,
title
:
'Hero'
,
description
:
'A large banner with a title.'
},
{
key
:
'toc'
,
title
:
'Table of Contents'
,
description
:
'A list of children pages.'
}
// { key: 'form', title: 'Form', description: '' }
],
block
:
{
key
:
false
}
{
key
:
'childlist'
,
title
:
'List Children Pages'
,
description
:
'Display a links list of all children of this page.'
,
icon
:
'mdi-format-list-text'
},
{
key
:
'tabs'
,
title
:
'Tabs'
,
description
:
'Organize content within tabs.'
,
icon
:
'mdi-tab'
}
]
}
},
computed
:
{
...
...
client/components/editor/editor-modal-editorselect.vue
View file @
7508d92f
...
...
@@ -106,43 +106,27 @@
v-flex(xs4)
v-hover
template(v-slot:default='{ hover }')
v-card.radius-7.
teal.
animated.fadeInUp(
v-card.radius-7.animated.fadeInUp(
hover
light
ripple
)
v-card-text.text-center(@click='')
v-card-text.text-center(@click='
fromTemplate
')
img(src='/svg/icon-cube.svg', alt='From Template', style='width: 42px; opacity: .5;')
.body-2.mt-1.teal--text.text--lighten-2 From Template
.caption.teal--text.text--lighten-1 Use an existing page / tree
v-fade-transition
v-overlay(
v-if='hover'
absolute
color='teal'
opacity='.8'
)
.body-2.mt-7 Coming Soon
.body-2.mt-1.teal--text From Template
.caption.grey--text Use an existing page...
v-flex(xs4)
v-hover
template(v-slot:default='{ hover }')
v-card.radius-7.
teal.
animated.fadeInUp.wait-p1s(
v-card.radius-7.animated.fadeInUp.wait-p1s(
hover
light
ripple
)
v-card-text.text-center(@click='')
img(src='/svg/icon-tree-structure.svg', alt='Tree View', style='width: 42px; opacity: .5;')
.body-2.mt-1.teal--text.text--lighten-2 Tree View
.caption.teal--text.text--lighten-1 List children pages
v-fade-transition
v-overlay(
v-if='hover'
absolute
color='teal'
opacity='.8'
)
.body-2.mt-7 Coming Soon
v-card-text.text-center(@click='selectEditor("redirect")')
img(src='/svg/icon-route.svg', alt='Redirection', style='width: 42px; opacity: .5;')
.body-2.mt-1.teal--text Redirection
.caption.grey--text Redirect the user to...
v-flex(xs4)
v-hover
template(v-slot:default='{ hover }')
...
...
@@ -190,11 +174,13 @@
opacity='.8'
)
.body-2 Coming Soon
page-selector(mode='select', v-model='templateDialogIsShown', :open-handler='fromTemplateHandle', :path='path', :locale='locale', must-exist)
</
template
>
<
script
>
import
_
from
'lodash'
import
{
sync
}
from
'vuex-pathify'
import
{
sync
,
get
}
from
'vuex-pathify'
export
default
{
props
:
{
...
...
@@ -204,22 +190,36 @@ export default {
}
},
data
()
{
return
{
}
return
{
templateDialogIsShown
:
false
}
},
computed
:
{
isShown
:
{
get
()
{
return
this
.
value
},
set
(
val
)
{
this
.
$emit
(
'input'
,
val
)
}
},
currentEditor
:
sync
(
'editor/editor'
)
currentEditor
:
sync
(
'editor/editor'
),
locale
:
get
(
'page/locale'
),
path
:
get
(
'page/path'
)
},
methods
:
{
selectEditor
(
name
)
{
selectEditor
(
name
)
{
this
.
currentEditor
=
`editor
${
_
.
startCase
(
name
)}
`
this
.
isShown
=
false
},
goBack
()
{
goBack
()
{
window
.
history
.
go
(
-
1
)
},
fromTemplate
()
{
this
.
templateDialogIsShown
=
true
},
fromTemplateHandle
({
id
})
{
this
.
templateDialogIsShown
=
false
this
.
isShown
=
false
this
.
$nextTick
(()
=>
{
window
.
location
.
assign
(
`/e/
${
this
.
locale
}
/
${
this
.
path
}
?from=
${
id
}
`
)
})
}
}
}
...
...
client/components/editor/editor-redirect.vue
0 → 100644
View file @
7508d92f
<
template
lang=
'pug'
>
.editor-redirect
.editor-redirect-main
.editor-redirect-editor
v-container.px-2.pt-1(fluid)
v-row(dense)
v-col(
cols='12'
lg='8'
offset-lg='2'
xl='6'
offset-xl='3'
)
v-card.pt-2
v-card-text
.pb-1
.subtitle-2.primary--text When a user reaches this page
.caption.grey--text.text--darken-1 and matches one of these rules...
v-timeline(dense)
v-slide-x-reverse-transition(group, hide-on-leave)
v-timeline-item(
key='cond-add-new'
hide-dot
)
v-btn(
color='primary'
@click=''
)
v-icon(left) mdi-plus
span Add Conditional Rule
v-timeline-item(
key='cond-none'
small
color='grey'
)
v-card.grey.lighten-5(flat)
v-card-text
.body-2: strong No conditional rule
em Add conditional rules to direct users to a different page based on their group.
v-timeline-item(
key='cond-rule-1'
small
color='primary'
)
v-card.blue-grey.lighten-5(flat)
v-card-text
.d-flex.align-center
.body-2: strong User is a member of any of these groups:
v-select.ml-3(
color='primary'
:items='groups'
item-text='name'
item-value='id'
multiple
solo
flat
hide-details
dense
chips
small-chips
)
v-divider.my-3
.d-flex.align-center
.body-2.mr-3 then redirect to
v-btn-toggle.mr-3(
v-model='fallbackMode'
mandatory
color='primary'
borderless
dense
)
v-btn.text-none(value='page') Page
v-btn.text-none(value='url') External URL
v-btn.mr-3(
v-if='fallbackMode === `page`'
color='primary'
)
v-icon(left) mdi-magnify
span Select Page...
v-text-field(
v-if='fallbackMode === `url`'
label='External URL'
outlined
hint='Required - Title of the API'
hide-details
v-model='fallbackUrl'
dense
single-line
)
v-divider.mb-5
.subtitle-2.primary--text Otherwise, redirect to...
.caption.grey--text.text--darken-1.pb-2 This fallback rule is mandatory and used if none of the conditional rules above applies.
.d-flex.align-center
v-btn-toggle.mr-3(
v-model='fallbackMode'
mandatory
color='primary'
borderless
dense
)
v-btn.text-none(value='page') Page
v-btn.text-none(value='url') External URL
v-btn.mr-3(
v-if='fallbackMode === `page`'
color='primary'
)
v-icon(left) mdi-magnify
span Select Page...
v-text-field(
v-if='fallbackMode === `url`'
label='External URL'
outlined
hint='Required - Title of the API'
hide-details
v-model='fallbackUrl'
dense
single-line
)
v-system-bar.editor-redirect-sysbar(dark, status, color='grey darken-3')
.caption.editor-redirect-sysbar-locale
{{
locale
.
toUpperCase
()
}}
.caption.px-3 /
{{
path
}}
template(v-if='$vuetify.breakpoint.mdAndUp')
v-spacer
.caption Redirect
v-spacer
.caption 0 rules
</
template
>
<
script
>
import
_
from
'lodash'
import
gql
from
'graphql-tag'
import
{
v4
as
uuid
}
from
'uuid'
import
{
get
,
sync
}
from
'vuex-pathify'
export
default
{
data
()
{
return
{
fallbackMode
:
'page'
,
fallbackUrl
:
'https://'
}
},
computed
:
{
isMobile
()
{
return
this
.
$vuetify
.
breakpoint
.
smAndDown
},
locale
:
get
(
'page/locale'
),
path
:
get
(
'page/path'
),
mode
:
get
(
'editor/mode'
),
activeModal
:
sync
(
'editor/activeModal'
)
},
methods
:
{
},
mounted
()
{
this
.
$store
.
set
(
'editor/editorKey'
,
'redirect'
)
if
(
this
.
mode
===
'create'
)
{
this
.
$store
.
set
(
'editor/content'
,
'<h1>Title</h1>
\
n
\
n<p>Some text here</p>'
)
}
},
apollo
:
{
groups
:
{
query
:
gql
`
{
groups {
list {
id
name
}
}
}
`
,
fetchPolicy
:
'network-only'
,
update
:
(
data
)
=>
data
.
groups
.
list
,
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading
${
isLoading
?
'Start'
:
'Stop'
}
`
,
'editor-redirect-groups'
)
}
}
}
}
</
script
>
<
style
lang=
'scss'
>
$editor-height
:
calc
(
100vh
-
64px
-
24px
);
$editor-height-mobile
:
calc
(
100vh
-
56px
-
16px
);
.editor-redirect
{
&
-main
{
display
:
flex
;
width
:
100%
;
}
&
-editor
{
background-color
:
darken
(
mc
(
'grey'
,
'100'
)
,
4
.5%
);
flex
:
1
1
50%
;
display
:
block
;
height
:
$editor-height
;
position
:
relative
;
@at-root
.theme--dark
&
{
background-color
:
darken
(
mc
(
'grey'
,
'900'
)
,
4
.5%
);
}
}
&
-sidebar
{
width
:
200px
;
}
&
-sysbar
{
padding-left
:
0
!
important
;
&
-locale
{
background-color
:
rgba
(
255
,
255
,
255
,.
25
);
display
:inline-flex
;
padding
:
0
12px
;
height
:
24px
;
width
:
63px
;
justify-content
:
center
;
align-items
:
center
;
}
}
}
</
style
>
client/static/svg/icon-route.svg
0 → 100644
View file @
7508d92f
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 128 128"
width=
"64px"
height=
"64px"
><path
fill=
"#FFF"
d=
"M51.8,90.9L51.8,90.9C54.5,87.3,56,82.8,56,78c0-12.2-9.8-22-22-22s-22,9.8-22,22c0,4.8,1.5,9.3,4.2,12.9l0,0h0c0.1,0.2,0.2,0.3,0.3,0.5L34,115l17.5-23.7C51.6,91.2,51.7,91.1,51.8,90.9L51.8,90.9z"
/><path
fill=
"#454B54"
d=
"M34,118L34,118c-1,0-1.8-0.5-2.4-1.2L14.1,93.1c-0.1-0.1-0.2-0.3-0.4-0.5C10.6,88.4,9,83.3,9,78c0-13.8,11.2-25,25-25s25,11.2,25,25c0,5.3-1.6,10.3-4.7,14.5c0,0-0.1,0.1-0.1,0.1l-0.3,0.4l-17.5,23.7C35.8,117.5,35,118,34,118z M34,59c-10.5,0-19,8.5-19,19c0,4,1.2,7.9,3.6,11.1c0.1,0.1,0.2,0.3,0.3,0.4L34,110l15.3-20.8c0,0,0,0,0-0.1C51.8,85.9,53,82,53,78C53,67.5,44.5,59,34,59z"
/><path
fill=
"#AA8F9D"
d=
"M84.3,35C82.8,33,82,30.5,82,28c0-6.6,5.4-12,12-12s12,5.4,12,12c0,2.5-0.8,5-2.3,7L94,48.2L84.3,35z"
/><path
fill=
"#454B54"
d=
"M94 51.2c-1 0-1.8-.5-2.4-1.2l-9.7-13.2C80 34.2 79 31.2 79 28c0-8.3 6.7-15 15-15s15 6.7 15 15c0 3.2-1 6.2-2.8 8.8L96.4 50C95.8 50.7 95 51.2 94 51.2zM94 19c-5 0-9 4-9 9 0 1.9.6 3.7 1.7 5.3l7.3 9.9 7.3-9.9c1.1-1.5 1.7-3.3 1.7-5.2C103 23 99 19 94 19zM108 118h-1c-1.7 0-3-1.3-3-3 0 0 0 0 0-.1-.6-1.2-.4-2.7.6-3.6 1.2-1.1 3.1-1 4.2.2l1.4 1.5c.8.9 1 2.1.5 3.2C110.3 117.3 109.2 118 108 118zM95 118h-3c-1.7 0-3-1.3-3-3s1.3-3 3-3h3c1.7 0 3 1.3 3 3S96.7 118 95 118zM80 118h-3c-1.7 0-3-1.3-3-3s1.3-3 3-3h3c1.7 0 3 1.3 3 3S81.7 118 80 118zM65 118h-3c-1.7 0-3-1.3-3-3s1.3-3 3-3h3c1.7 0 3 1.3 3 3S66.7 118 65 118zM50 118h-3c-1.7 0-3-1.3-3-3s1.3-3 3-3h3c1.7 0 3 1.3 3 3S51.7 118 50 118zM98.5 107.7c-.8 0-1.6-.3-2.2-1l-2-2.2c-1.1-1.2-1-3.1.2-4.2 1.2-1.1 3.1-1 4.2.2l2 2.2c1.1 1.2 1 3.1-.2 4.2C100 107.4 99.2 107.7 98.5 107.7zM88.4 96.7c-.8 0-1.6-.3-2.2-1l-2-2.2c-1.1-1.2-1-3.1.2-4.2 1.2-1.1 3.1-1 4.2.2l2 2.2c1.1 1.2 1 3.1-.2 4.2C89.8 96.4 89.1 96.7 88.4 96.7zM78.2 85.6c-.8 0-1.6-.3-2.2-1l-2-2.2c-1.1-1.2-1-3.1.2-4.2 1.2-1.1 3.1-1 4.2.2l2 2.2c1.1 1.2 1 3.1-.2 4.2C79.7 85.4 78.9 85.6 78.2 85.6zM77.7 74.1c-.6 0-1.3-.2-1.8-.6-1.3-1-1.6-2.9-.6-4.2l1.8-2.4c1-1.3 2.9-1.6 4.2-.6 1.3 1 1.6 2.9.6 4.2l-1.8 2.4C79.5 73.7 78.6 74.1 77.7 74.1zM86.7 62.1c-.6 0-1.3-.2-1.8-.6-1.3-1-1.6-2.9-.6-4.2l1.8-2.4c1-1.3 2.9-1.6 4.2-.6 1.3 1 1.6 2.9.6 4.2l-1.8 2.4C88.5 61.7 87.6 62.1 86.7 62.1z"
/><g><path
fill=
"#F48884"
d=
"M34 68A10 10 0 1 0 34 88A10 10 0 1 0 34 68Z"
/></g></svg>
\ No newline at end of file
server/modules/editor/redirect/definition.yml
0 → 100644
View file @
7508d92f
key
:
redirect
title
:
Redirection
description
:
Redirect the user
contentType
:
redirect
author
:
requarks.io
props
:
{}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment