mirror of https://github.com/Requarks/wiki.git
committed by
Nicolas Giard
14 changed files with 514 additions and 39 deletions
Unified View
Diff Options
-
5client/components/admin.vue
-
205client/components/admin/admin-comments.vue
-
1client/static/svg/icon-chat-bubble.svg
-
1server/core/kernel.js
-
10server/db/migrations-sqlite/2.3.14.js
-
16server/db/migrations/2.3.14.js
-
92server/graph/resolvers/comment.js
-
52server/graph/schemas/comment.graphql
-
100server/models/commentProviders.js
-
4server/modules/comments/commento/code.yml
-
17server/modules/comments/commento/definition.yml
-
19server/modules/comments/default/definition.yml
-
15server/modules/comments/disqus/code.yml
-
16server/modules/comments/disqus/definition.yml
@ -0,0 +1,205 @@ |
|||||
|
<template lang='pug'> |
||||
|
v-container(fluid, grid-list-lg) |
||||
|
v-layout(row, wrap) |
||||
|
v-flex(xs12) |
||||
|
.admin-header |
||||
|
img.animated.fadeInUp(src='/svg/icon-chat-bubble.svg', alt='Comments', style='width: 80px;') |
||||
|
.admin-header-title |
||||
|
.headline.primary--text.animated.fadeInLeft {{$t('admin:comments.title')}} |
||||
|
.subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{$t('admin:comments.subtitle')}} |
||||
|
v-spacer |
||||
|
v-btn.mx-1.animated.fadeInDown.wait-p2s(outlined, color='grey', @click='refresh', large) |
||||
|
v-icon mdi-refresh |
||||
|
v-btn.ml-1.animated.fadeInDown(color='success', @click='save', depressed, large) |
||||
|
v-icon(left) mdi-check |
||||
|
span {{$t('common:actions.apply')}} |
||||
|
|
||||
|
v-flex(lg3, xs12) |
||||
|
v-card.animated.fadeInUp |
||||
|
v-toolbar(flat, color='primary', dark, dense) |
||||
|
.subtitle-1 {{$t('admin:comments.providers')}} |
||||
|
v-list.py-0(two-line, dense) |
||||
|
template(v-for='(provider, idx) in providers') |
||||
|
v-list-item(:key='provider.key', @click='selectedProvider = provider.key', :disabled='!provider.isAvailable') |
||||
|
v-list-item-avatar(size='24') |
||||
|
v-icon(color='grey', v-if='!provider.isAvailable') mdi-minus-box-outline |
||||
|
v-icon(color='primary', v-else-if='provider.key === selectedProvider') mdi-checkbox-marked-circle-outline |
||||
|
v-icon(color='grey', v-else) mdi-checkbox-blank-circle-outline |
||||
|
v-list-item-content |
||||
|
v-list-item-title.body-2(:class='!provider.isAvailable ? `grey--text` : (selectedProvider === provider.key ? `primary--text` : ``)') {{ provider.title }} |
||||
|
v-list-item-subtitle: .caption(:class='!provider.isAvailable ? `grey--text text--lighten-1` : (selectedProvider === provider.key ? `blue--text ` : ``)') {{ provider.description }} |
||||
|
v-list-item-avatar(v-if='selectedProvider === provider.key', size='24') |
||||
|
v-icon.animated.fadeInLeft(color='primary', large) mdi-chevron-right |
||||
|
v-divider(v-if='idx < providers.length - 1') |
||||
|
|
||||
|
v-flex(lg9, xs12) |
||||
|
v-card.animated.fadeInUp.wait-p2s |
||||
|
v-toolbar(color='primary', dense, flat, dark) |
||||
|
.subtitle-1 {{provider.title}} |
||||
|
v-card-text |
||||
|
.providerlogo |
||||
|
img(:src='provider.logo', :alt='provider.title') |
||||
|
.caption.pt-3 {{provider.description}} |
||||
|
.caption.pb-3: a(:href='provider.website') {{provider.website}} |
||||
|
v-divider.mt-3 |
||||
|
.overline.my-5 {{$t('admin:comments.providerConfig')}} |
||||
|
.body-2.ml-3(v-if='!provider.config || provider.config.length < 1'): em {{$t('admin:comments.providerNoConfig')}} |
||||
|
template(v-else, v-for='cfg in provider.config') |
||||
|
v-select( |
||||
|
v-if='cfg.value.type === "string" && cfg.value.enum' |
||||
|
outlined |
||||
|
:items='cfg.value.enum' |
||||
|
:key='cfg.key' |
||||
|
:label='cfg.value.title' |
||||
|
v-model='cfg.value.value' |
||||
|
prepend-icon='mdi-cog-box' |
||||
|
:hint='cfg.value.hint ? cfg.value.hint : ""' |
||||
|
persistent-hint |
||||
|
:class='cfg.value.hint ? "mb-2" : ""' |
||||
|
) |
||||
|
v-switch.mb-3( |
||||
|
v-else-if='cfg.value.type === "boolean"' |
||||
|
:key='cfg.key' |
||||
|
:label='cfg.value.title' |
||||
|
v-model='cfg.value.value' |
||||
|
color='primary' |
||||
|
prepend-icon='mdi-cog-box' |
||||
|
:hint='cfg.value.hint ? cfg.value.hint : ""' |
||||
|
persistent-hint |
||||
|
inset |
||||
|
) |
||||
|
v-textarea( |
||||
|
v-else-if='cfg.value.type === "string" && cfg.value.multiline' |
||||
|
outlined |
||||
|
:key='cfg.key' |
||||
|
:label='cfg.value.title' |
||||
|
v-model='cfg.value.value' |
||||
|
prepend-icon='mdi-cog-box' |
||||
|
:hint='cfg.value.hint ? cfg.value.hint : ""' |
||||
|
persistent-hint |
||||
|
:class='cfg.value.hint ? "mb-2" : ""' |
||||
|
) |
||||
|
v-text-field( |
||||
|
v-else |
||||
|
outlined |
||||
|
:key='cfg.key' |
||||
|
:label='cfg.value.title' |
||||
|
v-model='cfg.value.value' |
||||
|
prepend-icon='mdi-cog-box' |
||||
|
:hint='cfg.value.hint ? cfg.value.hint : ""' |
||||
|
persistent-hint |
||||
|
:class='cfg.value.hint ? "mb-2" : ""' |
||||
|
) |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import _ from 'lodash' |
||||
|
import gql from 'graphql-tag' |
||||
|
|
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
providers: [], |
||||
|
selectedProvider: '', |
||||
|
provider: {} |
||||
|
} |
||||
|
}, |
||||
|
watch: { |
||||
|
selectedProvider(newValue, oldValue) { |
||||
|
this.provider = _.find(this.providers, ['key', newValue]) || {} |
||||
|
}, |
||||
|
providers(newValue, oldValue) { |
||||
|
this.selectedProvider = _.get(_.find(this.providers, 'isEnabled'), 'key', 'db') |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
async refresh() { |
||||
|
await this.$apollo.queries.providers.refetch() |
||||
|
this.$store.commit('showNotification', { |
||||
|
message: this.$t('admin:comments.listRefreshSuccess'), |
||||
|
style: 'success', |
||||
|
icon: 'cached' |
||||
|
}) |
||||
|
}, |
||||
|
async save() { |
||||
|
this.$store.commit(`loadingStart`, 'admin-comments-saveproviders') |
||||
|
try { |
||||
|
const resp = await this.$apollo.mutate({ |
||||
|
mutation: gql``, |
||||
|
variables: { |
||||
|
providers: this.providers.map(tgt => ({ |
||||
|
isEnabled: tgt.key === this.selectedProvider, |
||||
|
key: tgt.key, |
||||
|
config: tgt.config.map(cfg => ({...cfg, value: JSON.stringify({ v: cfg.value.value })})) |
||||
|
})) |
||||
|
} |
||||
|
}) |
||||
|
if (_.get(resp, 'data.comments.updateEngines.responseResult.succeeded', false)) { |
||||
|
this.$store.commit('showNotification', { |
||||
|
message: this.$t('admin:comments.configSaveSuccess'), |
||||
|
style: 'success', |
||||
|
icon: 'check' |
||||
|
}) |
||||
|
} else { |
||||
|
throw new Error(_.get(resp, 'data.comments.updateEngines.responseResult.message', this.$t('common:error.unexpected'))) |
||||
|
} |
||||
|
} catch (err) { |
||||
|
this.$store.commit('pushGraphError', err) |
||||
|
} |
||||
|
this.$store.commit(`loadingStop`, 'admin-comments-saveengines') |
||||
|
} |
||||
|
}, |
||||
|
apollo: { |
||||
|
providers: { |
||||
|
query: gql` |
||||
|
query { |
||||
|
comments { |
||||
|
providers { |
||||
|
isEnabled |
||||
|
key |
||||
|
title |
||||
|
description |
||||
|
logo |
||||
|
website |
||||
|
isAvailable |
||||
|
config { |
||||
|
key |
||||
|
value |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
`, |
||||
|
fetchPolicy: 'network-only', |
||||
|
update: (data) => _.cloneDeep(data.comments.providers).map(str => ({ |
||||
|
...str, |
||||
|
config: _.sortBy(str.config.map(cfg => ({ |
||||
|
...cfg, |
||||
|
value: JSON.parse(cfg.value) |
||||
|
})), [t => t.value.order]) |
||||
|
})), |
||||
|
watchLoading (isLoading) { |
||||
|
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-comments-refresh') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang='scss' scoped> |
||||
|
|
||||
|
.providerlogo { |
||||
|
width: 250px; |
||||
|
height: 85px; |
||||
|
float:right; |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
align-items: center; |
||||
|
|
||||
|
img { |
||||
|
max-width: 100%; |
||||
|
max-height: 50px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
</style> |
@ -0,0 +1 @@ |
|||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="96px" height="96px"><linearGradient id="r6aF76sThYJjByxe12PMJa" x1="26.5" x2="26.5" y1="16.5" y2="26.237" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#6dc7ff"/><stop offset="1" stop-color="#e6abff"/></linearGradient><path fill="url(#r6aF76sThYJjByxe12PMJa)" d="M32.832,25H20.168C19.523,25,19,24.477,19,23.832v-5.665C19,17.523,19.523,17,20.168,17 h12.665C33.477,17,34,17.523,34,18.168v5.665C34,24.477,33.477,25,32.832,25z"/><linearGradient id="r6aF76sThYJjByxe12PMJb" x1="32" x2="32" y1="9.553" y2="54.562" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><path fill="url(#r6aF76sThYJjByxe12PMJb)" d="M49,9H15c-2.758,0-5,2.242-5,4.996v28C10,44.754,12.242,47,15,47h15c0.551,0,1,0.445,1,0.996 v4.102c0,1.133,0.656,2.137,1.719,2.617c0.422,0.191,0.863,0.289,1.301,0.289c0.719,0,1.426-0.258,1.996-0.754l8.074-7.008 C44.273,47.086,44.508,47,44.746,47H49c2.758,0,5-2.246,5-5.004v-28C54,11.242,51.758,9,49,9z M52,41.996 C52,43.652,50.652,45,49,45h-4.254c-0.723,0-1.422,0.262-1.969,0.734l-8.074,7.008c-0.383,0.328-0.848,0.293-1.156,0.152 C33.383,52.82,33,52.594,33,52.098v-4.102C33,46.344,31.652,45,30,45H15c-1.652,0-3-1.348-3-3.004v-28C12,12.344,13.348,11,15,11 h34c1.652,0,3,1.344,3,2.996V41.996z"/><linearGradient id="r6aF76sThYJjByxe12PMJc" x1="32" x2="32" y1="9.553" y2="54.562" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><rect width="26" height="2" x="19" y="29" fill="url(#r6aF76sThYJjByxe12PMJc)"/><linearGradient id="r6aF76sThYJjByxe12PMJd" x1="28.5" x2="28.5" y1="9.553" y2="54.562" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><rect width="19" height="2" x="19" y="33" fill="url(#r6aF76sThYJjByxe12PMJd)"/><linearGradient id="r6aF76sThYJjByxe12PMJe" x1="32" x2="32" y1="9.553" y2="54.562" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><rect width="26" height="2" x="19" y="37" fill="url(#r6aF76sThYJjByxe12PMJe)"/></svg> |
@ -0,0 +1,10 @@ |
|||||
|
exports.up = knex => { |
||||
|
return knex.schema |
||||
|
.createTable('commentProviders', table => { |
||||
|
table.string('key').notNullable().primary() |
||||
|
table.boolean('isEnabled').notNullable().defaultTo(false) |
||||
|
table.json('config').notNullable() |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
exports.down = knex => { } |
@ -0,0 +1,16 @@ |
|||||
|
/* global WIKI */ |
||||
|
|
||||
|
exports.up = knex => { |
||||
|
const dbCompat = { |
||||
|
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`) |
||||
|
} |
||||
|
return knex.schema |
||||
|
.createTable('commentProviders', table => { |
||||
|
if (dbCompat.charset) { table.charset('utf8mb4') } |
||||
|
table.string('key').notNullable().primary() |
||||
|
table.boolean('isEnabled').notNullable().defaultTo(false) |
||||
|
table.json('config').notNullable() |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
exports.down = knex => { } |
@ -1,39 +1,57 @@ |
|||||
|
const _ = require('lodash') |
||||
|
const graphHelper = require('../../helpers/graph') |
||||
|
|
||||
|
/* global WIKI */ |
||||
|
|
||||
module.exports = { |
module.exports = { |
||||
// Query: {
|
|
||||
// comments(obj, args, context, info) {
|
|
||||
// return WIKI.models.Comment.findAll({ where: args })
|
|
||||
// }
|
|
||||
// },
|
|
||||
// Mutation: {
|
|
||||
// createComment(obj, args) {
|
|
||||
// return WIKI.models.Comment.create({
|
|
||||
// content: args.content,
|
|
||||
// author: args.userId,
|
|
||||
// document: args.documentId
|
|
||||
// })
|
|
||||
// },
|
|
||||
// deleteComment(obj, args) {
|
|
||||
// return WIKI.models.Comment.destroy({
|
|
||||
// where: {
|
|
||||
// id: args.id
|
|
||||
// },
|
|
||||
// limit: 1
|
|
||||
// })
|
|
||||
// },
|
|
||||
// modifyComment(obj, args) {
|
|
||||
// return WIKI.models.Comment.update({
|
|
||||
// content: args.content
|
|
||||
// }, {
|
|
||||
// where: { id: args.id }
|
|
||||
// })
|
|
||||
// }
|
|
||||
// },
|
|
||||
// Comment: {
|
|
||||
// author(cm) {
|
|
||||
// return cm.getAuthor()
|
|
||||
// },
|
|
||||
// document(cm) {
|
|
||||
// return cm.getDocument()
|
|
||||
// }
|
|
||||
// }
|
|
||||
|
Query: { |
||||
|
async comments() { return {} } |
||||
|
}, |
||||
|
Mutation: { |
||||
|
async comments() { return {} } |
||||
|
}, |
||||
|
CommentQuery: { |
||||
|
async providers(obj, args, context, info) { |
||||
|
const providers = await WIKI.models.commentProviders.getProviders() |
||||
|
return providers.map(provider => { |
||||
|
const providerInfo = _.find(WIKI.data.commentProviders, ['key', provider.key]) || {} |
||||
|
return { |
||||
|
...providerInfo, |
||||
|
...provider, |
||||
|
config: _.sortBy(_.transform(provider.config, (res, value, key) => { |
||||
|
const configData = _.get(providerInfo.props, key, false) |
||||
|
if (configData) { |
||||
|
res.push({ |
||||
|
key, |
||||
|
value: JSON.stringify({ |
||||
|
...configData, |
||||
|
value |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
}, []), 'key') |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
CommentMutation: { |
||||
|
async updateProviders(obj, args, context) { |
||||
|
try { |
||||
|
for (let provider of args.providers) { |
||||
|
await WIKI.models.providers.query().patch({ |
||||
|
isEnabled: provider.isEnabled, |
||||
|
config: _.reduce(provider.config, (result, value, key) => { |
||||
|
_.set(result, `${value.key}`, _.get(JSON.parse(value.value), 'v', null)) |
||||
|
return result |
||||
|
}, {}) |
||||
|
}).where('key', provider.key) |
||||
|
} |
||||
|
return { |
||||
|
responseResult: graphHelper.generateSuccess('Comment Providers updated successfully') |
||||
|
} |
||||
|
} catch (err) { |
||||
|
return graphHelper.generateError(err) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
} |
} |
@ -0,0 +1,52 @@ |
|||||
|
# =============================================== |
||||
|
# COMMENT |
||||
|
# =============================================== |
||||
|
|
||||
|
extend type Query { |
||||
|
comments: CommentQuery |
||||
|
} |
||||
|
|
||||
|
extend type Mutation { |
||||
|
comments: CommentMutation |
||||
|
} |
||||
|
|
||||
|
# ----------------------------------------------- |
||||
|
# QUERIES |
||||
|
# ----------------------------------------------- |
||||
|
|
||||
|
type CommentQuery { |
||||
|
providers: [CommentProvider] @auth(requires: ["manage:system"]) |
||||
|
} |
||||
|
|
||||
|
# ----------------------------------------------- |
||||
|
# MUTATIONS |
||||
|
# ----------------------------------------------- |
||||
|
|
||||
|
type CommentMutation { |
||||
|
updateProviders( |
||||
|
providers: [CommentProviderInput] |
||||
|
): DefaultResponse @auth(requires: ["manage:system"]) |
||||
|
|
||||
|
rebuildIndex: DefaultResponse @auth(requires: ["manage:system"]) |
||||
|
} |
||||
|
|
||||
|
# ----------------------------------------------- |
||||
|
# TYPES |
||||
|
# ----------------------------------------------- |
||||
|
|
||||
|
type CommentProvider { |
||||
|
isEnabled: Boolean! |
||||
|
key: String! |
||||
|
title: String! |
||||
|
description: String |
||||
|
logo: String |
||||
|
website: String |
||||
|
isAvailable: Boolean |
||||
|
config: [KeyValuePair] |
||||
|
} |
||||
|
|
||||
|
input CommentProviderInput { |
||||
|
isEnabled: Boolean! |
||||
|
key: String! |
||||
|
config: [KeyValuePairInput] |
||||
|
} |
@ -0,0 +1,100 @@ |
|||||
|
const Model = require('objection').Model |
||||
|
const fs = require('fs-extra') |
||||
|
const path = require('path') |
||||
|
const _ = require('lodash') |
||||
|
const yaml = require('js-yaml') |
||||
|
const commonHelper = require('../helpers/common') |
||||
|
|
||||
|
/* global WIKI */ |
||||
|
|
||||
|
/** |
||||
|
* CommentProvider model |
||||
|
*/ |
||||
|
module.exports = class CommentProvider extends Model { |
||||
|
static get tableName() { return 'commentProviders' } |
||||
|
static get idColumn() { return 'key' } |
||||
|
|
||||
|
static get jsonSchema () { |
||||
|
return { |
||||
|
type: 'object', |
||||
|
required: ['key', 'isEnabled'], |
||||
|
|
||||
|
properties: { |
||||
|
key: {type: 'string'}, |
||||
|
isEnabled: {type: 'boolean'} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static get jsonAttributes() { |
||||
|
return ['config'] |
||||
|
} |
||||
|
|
||||
|
static async getProvider(key) { |
||||
|
return WIKI.models.commentProviders.query().findOne({ key }) |
||||
|
} |
||||
|
|
||||
|
static async getProviders(isEnabled) { |
||||
|
const providers = await WIKI.models.commentProviders.query().where(_.isBoolean(isEnabled) ? { isEnabled } : {}) |
||||
|
return _.sortBy(providers, ['key']) |
||||
|
} |
||||
|
|
||||
|
static async refreshProvidersFromDisk() { |
||||
|
let trx |
||||
|
try { |
||||
|
const dbProviders = await WIKI.models.commentProviders.query() |
||||
|
|
||||
|
// -> Fetch definitions from disk
|
||||
|
const authDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/comments')) |
||||
|
let diskProviders = [] |
||||
|
for (let dir of authDirs) { |
||||
|
const def = await fs.readFile(path.join(WIKI.SERVERPATH, 'modules/comments', dir, 'definition.yml'), 'utf8') |
||||
|
diskProviders.push(yaml.safeLoad(def)) |
||||
|
} |
||||
|
WIKI.data.commentProviders = diskProviders.map(engine => ({ |
||||
|
...engine, |
||||
|
props: commonHelper.parseModuleProps(engine.props) |
||||
|
})) |
||||
|
|
||||
|
let newProviders = [] |
||||
|
for (let engine of WIKI.data.commentProviders) { |
||||
|
if (!_.some(dbProviders, ['key', engine.key])) { |
||||
|
newProviders.push({ |
||||
|
key: engine.key, |
||||
|
isEnabled: engine.key === 'default', |
||||
|
config: _.transform(engine.props, (result, value, key) => { |
||||
|
_.set(result, key, value.default) |
||||
|
return result |
||||
|
}, {}) |
||||
|
}) |
||||
|
} else { |
||||
|
const engineConfig = _.get(_.find(dbProviders, ['key', engine.key]), 'config', {}) |
||||
|
await WIKI.models.commentProviders.query().patch({ |
||||
|
config: _.transform(engine.props, (result, value, key) => { |
||||
|
if (!_.has(result, key)) { |
||||
|
_.set(result, key, value.default) |
||||
|
} |
||||
|
return result |
||||
|
}, engineConfig) |
||||
|
}).where('key', engine.key) |
||||
|
} |
||||
|
} |
||||
|
if (newProviders.length > 0) { |
||||
|
trx = await WIKI.models.Objection.transaction.start(WIKI.models.knex) |
||||
|
for (let engine of newProviders) { |
||||
|
await WIKI.models.commentProviders.query(trx).insert(engine) |
||||
|
} |
||||
|
await trx.commit() |
||||
|
WIKI.logger.info(`Loaded ${newProviders.length} new comment providers: [ OK ]`) |
||||
|
} else { |
||||
|
WIKI.logger.info(`No new comment providers found: [ SKIPPED ]`) |
||||
|
} |
||||
|
} catch (err) { |
||||
|
WIKI.logger.error(`Failed to scan or load new comment providers: [ FAILED ]`) |
||||
|
WIKI.logger.error(err) |
||||
|
if (trx) { |
||||
|
trx.rollback() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
main: | |
||||
|
<div id="commento"></div> |
||||
|
bodyEnd: | |
||||
|
<script defer src="{{instanceUrl}}/js/commento.js"></script> |
@ -0,0 +1,17 @@ |
|||||
|
key: commento |
||||
|
title: Commento |
||||
|
description: A fast, privacy-focused commenting platform. |
||||
|
author: requarks.io |
||||
|
logo: https://static.requarks.io/logo/commento.svg |
||||
|
website: https://commento.io/ |
||||
|
displayMode: footer |
||||
|
codeTemplate: true |
||||
|
isAvailable: true |
||||
|
props: |
||||
|
instanceUrl: |
||||
|
type: String |
||||
|
title: Instance URL |
||||
|
default: 'https://cdn.commento.io' |
||||
|
hint: The URL (without a trailing slash) to the Commento instance. Leave the default https://cdn.commento.io if using the cloud-hosted version. |
||||
|
order: 1 |
||||
|
|
@ -0,0 +1,19 @@ |
|||||
|
key: default |
||||
|
title: Default |
||||
|
description: Built-in advanced comments tool. |
||||
|
author: requarks.io |
||||
|
logo: https://static.requarks.io/logo/wikijs-butterfly.svg |
||||
|
website: https://wiki.js.org |
||||
|
displayMode: dynamic |
||||
|
codeTemplate: false |
||||
|
isAvailable: true |
||||
|
props: |
||||
|
displayMode: |
||||
|
type: String |
||||
|
title: Display mode |
||||
|
default: 'page' |
||||
|
enum: |
||||
|
- inline |
||||
|
- page |
||||
|
hint: Whether to display the comments under the content (inline) or on a dedicated page (page). |
||||
|
order: 1 |
@ -0,0 +1,15 @@ |
|||||
|
main: | |
||||
|
<div id="disqus_thread"></div> |
||||
|
bodyEnd: | |
||||
|
<script> |
||||
|
var disqus_config = function () { |
||||
|
this.page.url = {{pageUrl}}; |
||||
|
this.page.identifier = {{pageId}}; |
||||
|
}; |
||||
|
(function() { |
||||
|
var d = document, s = d.createElement('script'); |
||||
|
s.src = 'https://{{shortName}}.disqus.com/embed.js'; |
||||
|
s.setAttribute('data-timestamp', +new Date()); |
||||
|
(d.head || d.body).appendChild(s); |
||||
|
})(); |
||||
|
</script> |
@ -0,0 +1,16 @@ |
|||||
|
key: disqus |
||||
|
title: Disqus |
||||
|
description: Disqus help publishers power online discussions with comments. |
||||
|
author: requarks.io |
||||
|
logo: https://static.requarks.io/logo/disqus.svg |
||||
|
website: https://disqus.com/ |
||||
|
displayMode: footer |
||||
|
codeTemplate: true |
||||
|
isAvailable: true |
||||
|
props: |
||||
|
accountName: |
||||
|
type: String |
||||
|
title: Shortname |
||||
|
default: '' |
||||
|
hint: Unique identifier from Disqus to identify your website |
||||
|
order: 1 |
Write
Preview
Loading…
Cancel
Save