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
0b935446
Commit
0b935446
authored
Sep 08, 2018
by
Nicolas Giard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: admin rendering UI + module configuration UI + UI fixes
parent
92d0925d
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
212 additions
and
62 deletions
+212
-62
admin.vue
client/components/admin.vue
+11
-0
admin-api.vue
client/components/admin/admin-api.vue
+1
-0
admin-auth.vue
client/components/admin/admin-auth.vue
+1
-0
admin-contribute.vue
client/components/admin/admin-contribute.vue
+1
-0
admin-dev.vue
client/components/admin/admin-dev.vue
+1
-0
admin-editor.vue
client/components/admin/admin-editor.vue
+1
-0
admin-general.vue
client/components/admin/admin-general.vue
+1
-0
admin-groups-edit.vue
client/components/admin/admin-groups-edit.vue
+1
-0
admin-groups.vue
client/components/admin/admin-groups.vue
+1
-0
admin-locale.vue
client/components/admin/admin-locale.vue
+1
-0
admin-logging.vue
client/components/admin/admin-logging.vue
+1
-0
admin-pages.vue
client/components/admin/admin-pages.vue
+79
-0
admin-rendering.vue
client/components/admin/admin-rendering.vue
+103
-60
admin-search.vue
client/components/admin/admin-search.vue
+1
-0
admin-stats.vue
client/components/admin/admin-stats.vue
+1
-0
admin-storage.vue
client/components/admin/admin-storage.vue
+1
-0
admin-system.vue
client/components/admin/admin-system.vue
+1
-0
admin-theme.vue
client/components/admin/admin-theme.vue
+1
-0
admin-users.vue
client/components/admin/admin-users.vue
+1
-0
admin-utilities.vue
client/components/admin/admin-utilities.vue
+1
-0
nav-header.vue
client/components/common/nav-header.vue
+1
-1
definition.yml
server/modules/renderer/html-blockquotes/definition.yml
+1
-1
No files found.
client/components/admin.vue
View file @
0b935446
...
...
@@ -14,6 +14,9 @@
v-list-tile(to='/locale')
v-list-tile-avatar: v-icon language
v-list-tile-title
{{
$t
(
'admin:locale.title'
)
}}
v-list-tile(to='/pages')
v-list-tile-avatar: v-icon insert_drive_file
v-list-tile-title
{{
$t
(
'admin:pages.title'
)
}}
v-list-tile(to='/stats')
v-list-tile-avatar: v-icon show_chart
v-list-tile-title
{{
$t
(
'admin:stats.title'
)
}}
...
...
@@ -90,6 +93,7 @@ const router = new VueRouter({
{
path
:
'/dashboard'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-dashboard.vue'
)
},
{
path
:
'/general'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-general.vue'
)
},
{
path
:
'/locale'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-locale.vue'
)
},
{
path
:
'/pages'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-pages.vue'
)
},
{
path
:
'/stats'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-stats.vue'
)
},
{
path
:
'/theme'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-theme.vue'
)
},
{
path
:
'/groups'
,
component
:
()
=>
import
(
/* webpackChunkName: "admin" */
'./admin/admin-groups.vue'
)
},
...
...
@@ -154,4 +158,11 @@ export default {
}
}
.admin-header-icon
{
position
:
absolute
;
top
:
1rem
;
right
:
1rem
;
}
</
style
>
client/components/admin/admin-api.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(flat)
v-card(flat, tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') call_split
.headline.blue--text.text--darken-2 API
.subheading.grey--text Manage keys to access the API
v-card
...
...
client/components/admin/admin-auth.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"')
.pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') lock_outline
.headline.primary--text Authentication
.subheading.grey--text Configure the authentication settings of your wiki
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/admin/admin-contribute.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(flat)
v-card(flat, tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') favorite
.headline.primary--text
{{
$t
(
'admin:contribute.title'
)
}}
.subheading.grey--text
{{
$t
(
'admin:contribute.subtitle'
)
}}
v-card.pa-3
...
...
client/components/admin/admin-dev.vue
View file @
0b935446
<
template
lang=
'pug'
>
div
v-card(flat, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') weekend
.headline.primary--text Developer Tools
.subheading.grey--text ¯\_(ツ)_/¯
v-tabs(
...
...
client/components/admin/admin-editor.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"')
.pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') transform
.headline.primary--text Editor
.subheading.grey--text Configure the content editor
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/admin/admin-general.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') widgets
.headline.primary--text
{{
$t
(
'admin:general.title'
)
}}
.subheading.grey--text
{{
$t
(
'admin:general.subtitle'
)
}}
v-form.pt-3
...
...
client/components/admin/admin-groups-edit.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card
v-card(flat, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') people
.headline.blue--text.text--darken-2 Edit Group
.subheading.grey--text
{{
name
}}
v-btn(color='primary', fab, absolute, bottom, right, small, to='/groups'): v-icon arrow_upward
...
...
client/components/admin/admin-groups.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(flat)
v-card(flat, tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') people
.headline.blue--text.text--darken-2 Groups
.subheading.grey--text Manage groups and their permissions
v-card
...
...
client/components/admin/admin-locale.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') language
.headline.primary--text
{{
$t
(
'admin:locale.title'
)
}}
.subheading.grey--text
{{
$t
(
'admin:locale.subtitle'
)
}}
v-form.pt-3
...
...
client/components/admin/admin-logging.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"')
.pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') graphic_eq
.headline.primary--text Logging
.subheading.grey--text Configure the system logger(s)
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/admin/admin-pages.vue
0 → 100644
View file @
0b935446
<
template
lang=
'pug'
>
v-card(flat)
v-card(flat, tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') insert_drive_file
.headline.blue--text.text--darken-2 Pages
.subheading.grey--text Manage pages
v-card
v-card-title
v-btn(color='primary', dark, slot='activator')
v-icon(left) add
| New Page
v-btn(icon, @click='refresh')
v-icon.grey--text refresh
v-spacer
v-text-field(solo, append-icon='search', label='Search', single-line, hide-details, v-model='search')
v-data-table(
:items='groups'
:headers='headers'
:search='search'
:pagination.sync='pagination'
:rows-per-page-items='[15]'
hide-actions
)
template(slot='items', slot-scope='props')
tr.is-clickable(:active='props.selected', @click='$router.push("/e/" + props.item.id)')
td.text-xs-right
{{
props
.
item
.
id
}}
td
{{
props
.
item
.
name
}}
td
{{
props
.
item
.
userCount
}}
td
{{
props
.
item
.
createdAt
|
moment
(
'calendar'
)
}}
td
{{
props
.
item
.
updatedAt
|
moment
(
'calendar'
)
}}
template(slot='no-data')
v-alert.ma-3(icon='warning', :value='true', outline) No pages to display.
.text-xs-center.py-2(v-if='groups.length > 15')
v-pagination(v-model='pagination.page', :length='pages')
</
template
>
<
script
>
export
default
{
data
()
{
return
{
selectedGroup
:
{},
pagination
:
{},
groups
:
[],
headers
:
[
{
text
:
'ID'
,
value
:
'id'
,
width
:
50
,
align
:
'right'
},
{
text
:
'Title'
,
value
:
'title'
},
{
text
:
'Path'
,
value
:
'path'
},
{
text
:
'Created'
,
value
:
'createdAt'
,
width
:
250
},
{
text
:
'Last Updated'
,
value
:
'updatedAt'
,
width
:
250
}
],
search
:
''
}
},
computed
:
{
pages
()
{
if
(
this
.
pagination
.
rowsPerPage
==
null
||
this
.
pagination
.
totalItems
==
null
)
{
return
0
}
return
Math
.
ceil
(
this
.
pagination
.
totalItems
/
this
.
pagination
.
rowsPerPage
)
}
},
methods
:
{
async
refresh
()
{
// await this.$apollo.queries.groups.refetch()
this
.
$store
.
commit
(
'showNotification'
,
{
message
:
'Pages have been refreshed.'
,
style
:
'success'
,
icon
:
'cached'
})
}
}
}
</
script
>
<
style
lang=
'scss'
>
</
style
>
client/components/admin/admin-rendering.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') system_update_alt
.headline.primary--text Rendering
.subheading.grey--text Configure how content is rendered
v-layout.mt-3(row wrap)
...
...
@@ -17,7 +18,7 @@
v-expansion-panel.adm-rendering-pipeline(v-model='selectedCore')
v-expansion-panel-content(
hide-actions
v-for='core in
core
s'
v-for='core in
renderer
s'
:key='core.key'
)
v-toolbar(
...
...
@@ -27,24 +28,27 @@
dark
flat
)
v-spacer
.body-2
{{
core
.
input
}}
v-icon.mx-2 arrow_forward
.caption
{{
core
.
output
}}
v-list(two-line, dense)
v-spacer
v-list.py-0(two-line, dense)
template(v-for='(rdr, n) in core.children')
v-list-tile(
avatar
:key='rdr.key'
@click=''
@click='selectRenderer(rdr.key)'
:class='currentRenderer.key === rdr.key ? "blue lighten-5" : ""'
)
v-list-tile-avatar
v-icon(
color='grey
')
{{
rdr
.
icon
}}
v-icon(
:color='currentRenderer.key === rdr.key ? "primary" : "grey"
')
{{
rdr
.
icon
}}
v-list-tile-content
v-list-tile-title
{{
rdr
.
title
}}
v-list-tile-sub-title
{{
rdr
.
description
}}
v-list-tile-avatar
v-icon(color='green', small, v-if='rdr.isEnabled') lens
v-icon(color='red', small, v-else) trip_origin
status-indicator(v-if='rdr.isEnabled', positive, pulse)
status-indicator(v-else, negative, pulse)
v-divider.my-0(v-if='n < core.children.length - 1')
v-flex(lg9 xs12)
...
...
@@ -55,90 +59,129 @@
flat
dense
)
v-icon.mr-2 settings_applications
.subheading Markdown
v-icon chevron_right
.subheading Core
v-icon.mr-2
{{
currentRenderer
.
icon
}}
.subheading
{{
currentRenderer
.
title
}}
v-spacer
v-btn(flat, disabled)
v-icon(left) wrap_text
span Bypass
v-btn(flat, disabled)
v-icon(left) clear
span Remove
v-card-text
v-switch(
v-model='linkify'
label='Automatically convert links'
color='primary'
persistent-hint
hint='Links will automatically be converted to clickable links.'
)
v-divider.mt-3
v-switch(
v-model='linkify'
label='Automatically convert line breaks'
color='primary'
persistent-hint
hint='Add linebreaks within paragraphs.'
)
v-divider.mt-3
v-switch(
v-model='linkify'
label='Highlight code blocks'
color='primary'
persistent-hint
hint='Add syntax coloring to code blocks.'
.pt-3.mt-1
v-switch(
dark
color='white'
label='Enabled'
v-model='currentRenderer.isEnabled'
)
v-card-text.pb-4.pt-2.pl-4
v-subheader.pl-0 Rendering Module Configuration
.body-1.ml-3(v-if='!currentRenderer.config || currentRenderer.config.length < 1') This rendering module has no configuration options you can modify.
template(v-else, v-for='(cfg, idx) in currentRenderer.config')
v-select(
v-if='cfg.value.type === "string" && cfg.value.enum'
outline
background-color='grey lighten-2'
:items='cfg.value.enum'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
v-select.mt-3(
:items='["Light", "Dark"]'
v-model='codeTheme'
label='Code Color Theme'
outline
background-color='grey lighten-2'
)
v-switch(
v-else-if='cfg.value.type === "boolean"'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
color='primary'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
)
v-text-field(
v-else
outline
background-color='grey lighten-2'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
v-divider.my-3(v-if='idx < currentRenderer.config.length - 1')
v-card-chin
v-btn(
color='primary'
)
v-icon(left) check
span Apply Configuration
v-spacer
.caption.pr-3.grey--text Module:
{{
currentRenderer
.
key
}}
</
template
>
<
script
>
import
_
from
'lodash'
import
{
DepGraph
}
from
'dependency-graph'
import
{
StatusIndicator
}
from
'vue-status-indicator'
import
renderersQuery
from
'gql/admin/rendering/rendering-query-renderers.gql'
export
default
{
components
:
{
StatusIndicator
},
data
()
{
return
{
selectedCore
:
0
,
linkify
:
true
,
codeTheme
:
'Light'
,
renderers
:
[]
}
},
computed
:
{
cores
()
{
return
_
.
filter
(
this
.
renderers
,
[
'dependsOn'
,
null
]).
map
(
core
=>
{
core
.
children
=
_
.
concat
([
_
.
cloneDeep
(
core
)],
_
.
filter
(
this
.
renderers
,
[
'dependsOn'
,
core
.
key
]))
return
core
})
selectedCore
:
-
1
,
renderers
:
[],
currentRenderer
:
{}
}
},
watch
:
{
renderers
(
newValue
,
oldValue
)
{
_
.
delay
(()
=>
{
this
.
selectedCore
=
_
.
findIndex
(
this
.
cores
,
[
'key'
,
'markdownCore'
])
this
.
selectedCore
=
_
.
findIndex
(
newValue
,
[
'key'
,
'markdownCore'
])
this
.
selectRenderer
(
'markdownCore'
)
},
500
)
}
},
methods
:
{
selectRenderer
(
key
)
{
this
.
renderers
.
map
(
rdr
=>
{
if
(
_
.
some
(
rdr
.
children
,
[
'key'
,
key
]))
{
this
.
currentRenderer
=
_
.
find
(
rdr
.
children
,
[
'key'
,
key
])
}
})
}
},
apollo
:
{
renderers
:
{
query
:
renderersQuery
,
fetchPolicy
:
'network-only'
,
update
:
(
data
)
=>
_
.
cloneDeep
(
data
.
rendering
.
renderers
).
map
(
str
=>
({...
str
,
config
:
str
.
config
.
map
(
cfg
=>
({...
cfg
,
value
:
JSON
.
parse
(
cfg
.
value
)}))})),
update
:
(
data
)
=>
{
let
renderers
=
_
.
cloneDeep
(
data
.
rendering
.
renderers
).
map
(
str
=>
({...
str
,
config
:
str
.
config
.
map
(
cfg
=>
({...
cfg
,
value
:
JSON
.
parse
(
cfg
.
value
)}))}))
// Build tree
const
graph
=
new
DepGraph
({
circular
:
true
})
const
rawCores
=
_
.
filter
(
renderers
,
[
'dependsOn'
,
null
]).
map
(
core
=>
{
core
.
children
=
_
.
concat
([
_
.
cloneDeep
(
core
)],
_
.
filter
(
renderers
,
[
'dependsOn'
,
core
.
key
]))
return
core
})
// Build dependency graph
rawCores
.
map
(
core
=>
{
graph
.
addNode
(
core
.
key
)
})
rawCores
.
map
(
core
=>
{
rawCores
.
map
(
coreTarget
=>
{
if
(
core
.
key
!==
coreTarget
.
key
)
{
if
(
core
.
output
===
coreTarget
.
input
)
{
graph
.
addDependency
(
core
.
key
,
coreTarget
.
key
)
}
}
})
})
// Reorder cores in reverse dependency order
let
orderedCores
=
[]
_
.
reverse
(
graph
.
overallOrder
()).
map
(
coreKey
=>
{
orderedCores
.
push
(
_
.
find
(
rawCores
,
[
'key'
,
coreKey
]))
})
return
orderedCores
},
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading
${
isLoading
?
'Start'
:
'Stop'
}
`
,
'admin-rendering-refresh'
)
}
...
...
client/components/admin/admin-search.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"')
.pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') search
.headline.primary--text Search Engine
.subheading.grey--text Configure the search capabilities of your wiki
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/admin/admin-stats.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') show_chart
.headline.primary--text Statistics
.subheading.grey--text Useful information about your wiki
.pa-3
...
...
client/components/admin/admin-storage.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"')
.pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') storage
.headline.primary--text Storage
.subheading.grey--text Set backup and sync targets for your content
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/admin/admin-system.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') tune
.headline.primary--text
{{
$t
(
'admin:system.title'
)
}}
.subheading.grey--text
{{
$t
(
'admin:system.subtitle'
)
}}
v-layout.mt-3(row wrap)
...
...
client/components/admin/admin-theme.vue
View file @
0b935446
...
...
@@ -2,6 +2,7 @@
v-container(fluid, fill-height, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') palette
.headline.primary--text Theme
.subheading.grey--text Modify the look & feel of your wiki
v-form.pt-3
...
...
client/components/admin/admin-users.vue
View file @
0b935446
<
template
lang=
'pug'
>
v-card(flat)
v-card(flat, tile, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') perm_identity
.headline.blue--text.text--darken-2 Users
.subheading.grey--text Manage users
v-card
...
...
client/components/admin/admin-utilities.vue
View file @
0b935446
<
template
lang=
'pug'
>
div
v-card(flat, :color='$vuetify.dark ? "grey darken-4" : "grey lighten-5"').pa-3.pt-4
.admin-header-icon: v-icon(size='80', color='grey lighten-2') build
.headline.primary--text Utilities
.subheading.grey--text Maintenance and troubleshooting tools
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
...
...
client/components/common/nav-header.vue
View file @
0b935446
...
...
@@ -19,7 +19,7 @@
v-menu(open-on-hover, offset-y, bottom, left, min-width='250')
v-toolbar-side-icon(slot='activator')
v-icon view_module
v-list(dense).py-0
v-list(dense
, :light='!$vuetify.dark'
).py-0
v-list-tile(avatar, href='/')
v-list-tile-avatar: v-icon(color='blue') home
v-list-tile-content Home
...
...
server/modules/renderer/html-blockquotes/definition.yml
View file @
0b935446
key
:
htmlBlockquotes
title
:
Blockquotes
description
:
Embed audio players for audio content
description
:
Parse blockquotes box styling
author
:
requarks.io
icon
:
insert_comment
enabledDefault
:
true
...
...
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