mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'master' of github.com:Human-Connection/Human-Connection into 1017-send-out-notifications-on-create-omment
This commit is contained in:
commit
21aa729edb
@ -55,7 +55,7 @@
|
|||||||
"cheerio": "~1.0.0-rc.3",
|
"cheerio": "~1.0.0-rc.3",
|
||||||
"cors": "~2.8.5",
|
"cors": "~2.8.5",
|
||||||
"cross-env": "~5.2.0",
|
"cross-env": "~5.2.0",
|
||||||
"date-fns": "2.0.0-beta.3",
|
"date-fns": "2.0.0-beta.4",
|
||||||
"debug": "~4.1.1",
|
"debug": "~4.1.1",
|
||||||
"dotenv": "~8.0.0",
|
"dotenv": "~8.0.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
@ -78,7 +78,7 @@
|
|||||||
"metascraper-date": "^5.6.5",
|
"metascraper-date": "^5.6.5",
|
||||||
"metascraper-description": "^5.6.5",
|
"metascraper-description": "^5.6.5",
|
||||||
"metascraper-image": "^5.6.5",
|
"metascraper-image": "^5.6.5",
|
||||||
"metascraper-lang": "^5.6.3",
|
"metascraper-lang": "^5.6.5",
|
||||||
"metascraper-lang-detector": "^4.8.5",
|
"metascraper-lang-detector": "^4.8.5",
|
||||||
"metascraper-logo": "^5.6.5",
|
"metascraper-logo": "^5.6.5",
|
||||||
"metascraper-publisher": "^5.6.5",
|
"metascraper-publisher": "^5.6.5",
|
||||||
@ -87,9 +87,10 @@
|
|||||||
"metascraper-url": "^5.6.5",
|
"metascraper-url": "^5.6.5",
|
||||||
"metascraper-video": "^5.6.5",
|
"metascraper-video": "^5.6.5",
|
||||||
"metascraper-youtube": "^5.6.3",
|
"metascraper-youtube": "^5.6.3",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
"neo4j-driver": "~1.7.5",
|
"neo4j-driver": "~1.7.5",
|
||||||
"neo4j-graphql-js": "^2.6.3",
|
"neo4j-graphql-js": "^2.6.3",
|
||||||
"neode": "^0.3.0",
|
"neode": "^0.3.1",
|
||||||
"node-fetch": "~2.6.0",
|
"node-fetch": "~2.6.0",
|
||||||
"nodemailer": "^6.3.0",
|
"nodemailer": "^6.3.0",
|
||||||
"npm-run-all": "~4.1.5",
|
"npm-run-all": "~4.1.5",
|
||||||
|
|||||||
@ -64,7 +64,7 @@ describe('currentUser { notifications }', () => {
|
|||||||
let post
|
let post
|
||||||
const title = 'Mentioning Al Capone'
|
const title = 'Mentioning Al Capone'
|
||||||
const content =
|
const content =
|
||||||
'Hey <a class="mention" href="/profile/you/al-capone">@al-capone</a> how do you do?'
|
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone">@al-capone</a> how do you do?'
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const createPostMutation = gql`
|
const createPostMutation = gql`
|
||||||
@ -88,7 +88,7 @@ describe('currentUser { notifications }', () => {
|
|||||||
|
|
||||||
it('sends you a notification', async () => {
|
it('sends you a notification', async () => {
|
||||||
const expectedContent =
|
const expectedContent =
|
||||||
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
|
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
|
||||||
const expected = {
|
const expected = {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
notifications: [
|
notifications: [
|
||||||
@ -108,14 +108,22 @@ describe('currentUser { notifications }', () => {
|
|||||||
).resolves.toEqual(expected)
|
).resolves.toEqual(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('who mentions me again', () => {
|
describe('who mentions me many times', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const updatedContent = `${post.content} One more mention to <a href="/profile/you" class="mention">@al-capone</a>`
|
const updatedContent = `
|
||||||
// The response `post.content` contains a link but the XSSmiddleware
|
One more mention to
|
||||||
// should have the `mention` CSS class removed. I discovered this
|
<a data-mention-id="you" class="mention" href="/profile/you">
|
||||||
// during development and thought: A feature not a bug! This way we
|
@al-capone
|
||||||
// can encode a re-mentioning of users when you edit your post or
|
</a>
|
||||||
// comment.
|
and again:
|
||||||
|
<a data-mention-id="you" class="mention" href="/profile/you">
|
||||||
|
@al-capone
|
||||||
|
</a>
|
||||||
|
and again
|
||||||
|
<a data-mention-id="you" class="mention" href="/profile/you">
|
||||||
|
@al-capone
|
||||||
|
</a>
|
||||||
|
`
|
||||||
const updatePostMutation = gql`
|
const updatePostMutation = gql`
|
||||||
mutation($id: ID!, $title: String!, $content: String!) {
|
mutation($id: ID!, $title: String!, $content: String!) {
|
||||||
UpdatePost(id: $id, content: $content, title: $title) {
|
UpdatePost(id: $id, content: $content, title: $title) {
|
||||||
@ -136,7 +144,7 @@ describe('currentUser { notifications }', () => {
|
|||||||
|
|
||||||
it('creates exactly one more notification', async () => {
|
it('creates exactly one more notification', async () => {
|
||||||
const expectedContent =
|
const expectedContent =
|
||||||
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do? One more mention to <a href="/profile/you" target="_blank">@al-capone</a>'
|
'<br>One more mention to<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>and again:<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>and again<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>'
|
||||||
const expected = {
|
const expected = {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
notifications: [
|
notifications: [
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
import cheerio from 'cheerio'
|
import cheerio from 'cheerio'
|
||||||
const ID_REGEX = /\/profile\/([\w\-.!~*'"(),]+)/g
|
|
||||||
|
|
||||||
export default function(content) {
|
export default function(content) {
|
||||||
if (!content) return []
|
if (!content) return []
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
const urls = $('.mention')
|
let userIds = $('a.mention[data-mention-id]')
|
||||||
.map((_, el) => {
|
.map((_, el) => {
|
||||||
return $(el).attr('href')
|
return $(el).attr('data-mention-id')
|
||||||
})
|
})
|
||||||
.get()
|
.get()
|
||||||
const ids = []
|
userIds = userIds.map(id => id.trim()).filter(id => !!id)
|
||||||
urls.forEach(url => {
|
return userIds
|
||||||
let match
|
|
||||||
while ((match = ID_REGEX.exec(url)) != null) {
|
|
||||||
ids.push(match[1])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return ids
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
import extractMentionedUsers from './extractMentionedUsers'
|
import extractMentionedUsers from './extractMentionedUsers'
|
||||||
|
|
||||||
|
const contentWithMentions =
|
||||||
|
'<p>Something inspirational about <a href="/profile/u2" class="not-a-mention" data-mention-id="bobs-id" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" data-mention-id="u3" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
|
const contentEmptyMentions =
|
||||||
|
'<p>Something inspirational about <a href="/profile/u2" data-mention-id="" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" data-mention-id target="_blank">@jenny-rostock</a>.</p>'
|
||||||
|
const contentWithPlainLinks =
|
||||||
|
'<p>Something inspirational about <a class="mention" href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
|
|
||||||
describe('extractMentionedUsers', () => {
|
describe('extractMentionedUsers', () => {
|
||||||
describe('content undefined', () => {
|
describe('content undefined', () => {
|
||||||
it('returns empty array', () => {
|
it('returns empty array', () => {
|
||||||
@ -7,53 +14,17 @@ describe('extractMentionedUsers', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('searches through links', () => {
|
it('ignores links without .mention class', () => {
|
||||||
it('ignores links without .mention class', () => {
|
expect(extractMentionedUsers(contentWithPlainLinks)).toEqual([])
|
||||||
const content =
|
})
|
||||||
'<p>Something inspirational about <a href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual([])
|
describe('given a link with .mention class and `data-mention-id` attribute ', () => {
|
||||||
|
it('extracts ids', () => {
|
||||||
|
expect(extractMentionedUsers(contentWithMentions)).toEqual(['u3'])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given a link with .mention class', () => {
|
it('ignores empty `data-mention-id` attributes', () => {
|
||||||
it('extracts ids', () => {
|
expect(extractMentionedUsers(contentEmptyMentions)).toEqual([])
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="/profile/u2" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('handles links', () => {
|
|
||||||
it('with slug and id', () => {
|
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('with domains', () => {
|
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="http://localhost:3000/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('special characters', () => {
|
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="http://localhost:3000/profile/u!*(),2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u.~-3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual(['u!*(),2', 'u.~-3'])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('does not crash if', () => {
|
|
||||||
it('`href` contains no user id', () => {
|
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="/profile" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual([])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('`href` is empty or invalid', () => {
|
|
||||||
const content =
|
|
||||||
'<p>Something inspirational about <a href="" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="not-a-url" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
|
||||||
expect(extractMentionedUsers(content)).toEqual([])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,30 +2,16 @@ import walkRecursive from '../helpers/walkRecursive'
|
|||||||
// import { getByDot, setByDot, getItems, replaceItems } from 'feathers-hooks-common'
|
// import { getByDot, setByDot, getItems, replaceItems } from 'feathers-hooks-common'
|
||||||
import sanitizeHtml from 'sanitize-html'
|
import sanitizeHtml from 'sanitize-html'
|
||||||
// import { isEmpty, intersection } from 'lodash'
|
// import { isEmpty, intersection } from 'lodash'
|
||||||
import cheerio from 'cheerio'
|
|
||||||
import linkifyHtml from 'linkifyjs/html'
|
import linkifyHtml from 'linkifyjs/html'
|
||||||
|
|
||||||
const embedToAnchor = content => {
|
|
||||||
const $ = cheerio.load(content)
|
|
||||||
$('div[data-url-embed]').each((i, el) => {
|
|
||||||
const url = el.attribs['data-url-embed']
|
|
||||||
const aTag = $(`<a href="${url}" target="_blank" data-url-embed="">${url}</a>`)
|
|
||||||
$(el).replaceWith(aTag)
|
|
||||||
})
|
|
||||||
return $('body').html()
|
|
||||||
}
|
|
||||||
|
|
||||||
function clean(dirty) {
|
function clean(dirty) {
|
||||||
if (!dirty) {
|
if (!dirty) {
|
||||||
return dirty
|
return dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert embeds to a-tags
|
|
||||||
dirty = embedToAnchor(dirty)
|
|
||||||
dirty = linkifyHtml(dirty)
|
dirty = linkifyHtml(dirty)
|
||||||
dirty = sanitizeHtml(dirty, {
|
dirty = sanitizeHtml(dirty, {
|
||||||
allowedTags: [
|
allowedTags: [
|
||||||
'iframe',
|
|
||||||
'img',
|
'img',
|
||||||
'p',
|
'p',
|
||||||
'h3',
|
'h3',
|
||||||
@ -50,35 +36,24 @@ function clean(dirty) {
|
|||||||
a: ['href', 'class', 'target', 'data-*', 'contenteditable'],
|
a: ['href', 'class', 'target', 'data-*', 'contenteditable'],
|
||||||
span: ['contenteditable', 'class', 'data-*'],
|
span: ['contenteditable', 'class', 'data-*'],
|
||||||
img: ['src'],
|
img: ['src'],
|
||||||
iframe: ['src', 'class', 'frameborder', 'allowfullscreen'],
|
|
||||||
},
|
},
|
||||||
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
|
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
|
||||||
parser: {
|
parser: {
|
||||||
lowerCaseTags: true,
|
lowerCaseTags: true,
|
||||||
},
|
},
|
||||||
transformTags: {
|
transformTags: {
|
||||||
iframe: function(tagName, attribs) {
|
|
||||||
return {
|
|
||||||
tagName: 'a',
|
|
||||||
text: attribs.src,
|
|
||||||
attribs: {
|
|
||||||
href: attribs.src,
|
|
||||||
target: '_blank',
|
|
||||||
'data-url-embed': '',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
h1: 'h3',
|
h1: 'h3',
|
||||||
h2: 'h3',
|
h2: 'h3',
|
||||||
h3: 'h3',
|
h3: 'h3',
|
||||||
h4: 'h4',
|
h4: 'h4',
|
||||||
h5: 'strong',
|
h5: 'strong',
|
||||||
i: 'em',
|
i: 'em',
|
||||||
a: function(tagName, attribs) {
|
a: (tagName, attribs) => {
|
||||||
return {
|
return {
|
||||||
tagName: 'a',
|
tagName: 'a',
|
||||||
attribs: {
|
attribs: {
|
||||||
href: attribs.href,
|
...attribs,
|
||||||
|
href: attribs.href || '',
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener noreferrer nofollow',
|
rel: 'noopener noreferrer nofollow',
|
||||||
},
|
},
|
||||||
@ -86,33 +61,6 @@ function clean(dirty) {
|
|||||||
},
|
},
|
||||||
b: 'strong',
|
b: 'strong',
|
||||||
s: 'strike',
|
s: 'strike',
|
||||||
img: function(tagName, attribs) {
|
|
||||||
const src = attribs.src
|
|
||||||
|
|
||||||
if (!src) {
|
|
||||||
// remove broken images
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (isEmpty(hook.result)) {
|
|
||||||
// const config = hook.app.get('thumbor')
|
|
||||||
// if (config && src.indexOf(config < 0)) {
|
|
||||||
// // download image
|
|
||||||
// // const ThumborUrlHelper = require('../helper/thumbor-helper')
|
|
||||||
// // const Thumbor = new ThumborUrlHelper(config.key || null, config.url || null)
|
|
||||||
// // src = Thumbor
|
|
||||||
// // .setImagePath(src)
|
|
||||||
// // .buildUrl('740x0')
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return {
|
|
||||||
tagName: 'img',
|
|
||||||
attribs: {
|
|
||||||
// TODO: use environment variables
|
|
||||||
src: `http://localhost:3050/images?url=${src}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -120,8 +68,6 @@ function clean(dirty) {
|
|||||||
dirty = dirty
|
dirty = dirty
|
||||||
// remove all tags with "space only"
|
// remove all tags with "space only"
|
||||||
.replace(/<[a-z-]+>[\s]+<\/[a-z-]+>/gim, '')
|
.replace(/<[a-z-]+>[\s]+<\/[a-z-]+>/gim, '')
|
||||||
// remove all iframes
|
|
||||||
.replace(/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/gim, '')
|
|
||||||
.replace(/[\n]{3,}/gim, '\n\n')
|
.replace(/[\n]{3,}/gim, '\n\n')
|
||||||
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
||||||
|
|
||||||
@ -144,8 +90,7 @@ const fields = ['content', 'contentExcerpt']
|
|||||||
export default {
|
export default {
|
||||||
Mutation: async (resolve, root, args, context, info) => {
|
Mutation: async (resolve, root, args, context, info) => {
|
||||||
args = walkRecursive(args, fields, clean)
|
args = walkRecursive(args, fields, clean)
|
||||||
const result = await resolve(root, args, context, info)
|
return resolve(root, args, context, info)
|
||||||
return result
|
|
||||||
},
|
},
|
||||||
Query: async (resolve, root, args, context, info) => {
|
Query: async (resolve, root, args, context, info) => {
|
||||||
const result = await resolve(root, args, context, info)
|
const result = await resolve(root, args, context, info)
|
||||||
|
|||||||
26
backend/src/schema/resolvers/embeds/findProvider.js
Normal file
26
backend/src/schema/resolvers/embeds/findProvider.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import minimatch from 'minimatch'
|
||||||
|
|
||||||
|
let oEmbedProvidersFile = fs.readFileSync(path.join(__dirname, './providers.json'), 'utf8')
|
||||||
|
// some providers allow a format parameter
|
||||||
|
// we need JSON
|
||||||
|
oEmbedProvidersFile = oEmbedProvidersFile.replace(/\{format\}/g, 'json')
|
||||||
|
const oEmbedProviders = JSON.parse(oEmbedProvidersFile)
|
||||||
|
|
||||||
|
export default function(embedUrl) {
|
||||||
|
for (const provider of oEmbedProviders) {
|
||||||
|
for (const endpoint of provider.endpoints) {
|
||||||
|
const { schemes = [], url } = endpoint
|
||||||
|
if (schemes.some(scheme => minimatch(embedUrl, scheme))) return url
|
||||||
|
}
|
||||||
|
const { hostname } = new URL(embedUrl)
|
||||||
|
if (provider.provider_url.includes(hostname)) {
|
||||||
|
const {
|
||||||
|
endpoints: [{ url }],
|
||||||
|
} = provider
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
35
backend/src/schema/resolvers/embeds/findProvider.spec.js
Normal file
35
backend/src/schema/resolvers/embeds/findProvider.spec.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import findProvider from './findProvider'
|
||||||
|
|
||||||
|
describe('Vimeo', () => {
|
||||||
|
it('matches `https://vimeo.com/showcase/2098620/video/4082288`', () => {
|
||||||
|
expect(findProvider('https://vimeo.com/showcase/2098620/video/4082288')).toEqual(
|
||||||
|
'https://vimeo.com/api/oembed.json',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('RiffReporter', () => {
|
||||||
|
it('matches `https://www.riffreporter.de/flugbegleiter-koralle/`', () => {
|
||||||
|
expect(findProvider('https://www.riffreporter.de/flugbegleiter-koralle/')).toEqual(
|
||||||
|
'https://www.riffreporter.de/service/oembed',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Youtube', () => {
|
||||||
|
it('matches `https://www.youtube.com/watch?v=qkdXAtO40Fo`', () => {
|
||||||
|
expect(findProvider('https://www.youtube.com/watch?v=qkdXAtO40Fo')).toEqual(
|
||||||
|
'https://www.youtube.com/oembed',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches `https://youtu.be/qkdXAtO40Fo`', () => {
|
||||||
|
expect(findProvider(`https://youtu.be/qkdXAtO40Fo`)).toEqual('https://www.youtube.com/oembed')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches `https://youtu.be/qkdXAtO40Fo?t=41`', () => {
|
||||||
|
expect(findProvider(`https://youtu.be/qkdXAtO40Fo?t=41`)).toEqual(
|
||||||
|
'https://www.youtube.com/oembed',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,12 +1,11 @@
|
|||||||
import Metascraper from 'metascraper'
|
import Metascraper from 'metascraper'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
import { ApolloError } from 'apollo-server'
|
import { ApolloError } from 'apollo-server'
|
||||||
import isEmpty from 'lodash/isEmpty'
|
import isEmpty from 'lodash/isEmpty'
|
||||||
import isArray from 'lodash/isArray'
|
import isArray from 'lodash/isArray'
|
||||||
import mergeWith from 'lodash/mergeWith'
|
import mergeWith from 'lodash/mergeWith'
|
||||||
|
import findProvider from './findProvider'
|
||||||
|
|
||||||
const error = require('debug')('embed:error')
|
const error = require('debug')('embed:error')
|
||||||
|
|
||||||
@ -30,24 +29,11 @@ const metascraper = Metascraper([
|
|||||||
// require('./rules/metascraper-embed')()
|
// require('./rules/metascraper-embed')()
|
||||||
])
|
])
|
||||||
|
|
||||||
let oEmbedProvidersFile = fs.readFileSync(path.join(__dirname, './providers.json'), 'utf8')
|
|
||||||
|
|
||||||
// some providers allow a format parameter
|
|
||||||
// we need JSON
|
|
||||||
oEmbedProvidersFile = oEmbedProvidersFile.replace('{format}', 'json')
|
|
||||||
|
|
||||||
const oEmbedProviders = JSON.parse(oEmbedProvidersFile)
|
|
||||||
|
|
||||||
const fetchEmbed = async url => {
|
const fetchEmbed = async url => {
|
||||||
const provider = oEmbedProviders.find(provider => {
|
let endpointUrl = findProvider(url)
|
||||||
return provider.provider_url.includes(url.hostname)
|
if (!endpointUrl) return {}
|
||||||
})
|
endpointUrl = new URL(endpointUrl)
|
||||||
if (!provider) return {}
|
endpointUrl.searchParams.append('url', url)
|
||||||
const {
|
|
||||||
endpoints: [endpoint],
|
|
||||||
} = provider
|
|
||||||
const endpointUrl = new URL(endpoint.url)
|
|
||||||
endpointUrl.searchParams.append('url', url.href)
|
|
||||||
endpointUrl.searchParams.append('format', 'json')
|
endpointUrl.searchParams.append('format', 'json')
|
||||||
let json
|
let json
|
||||||
try {
|
try {
|
||||||
@ -70,7 +56,7 @@ const fetchEmbed = async url => {
|
|||||||
const fetchResource = async url => {
|
const fetchResource = async url => {
|
||||||
const response = await fetch(url)
|
const response = await fetch(url)
|
||||||
const html = await response.text()
|
const html = await response.text()
|
||||||
const resource = await metascraper({ html, url: url.href })
|
const resource = await metascraper({ html, url })
|
||||||
return {
|
return {
|
||||||
sources: ['resource'],
|
sources: ['resource'],
|
||||||
...resource,
|
...resource,
|
||||||
@ -78,12 +64,6 @@ const fetchResource = async url => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function scrape(url) {
|
export default async function scrape(url) {
|
||||||
url = new URL(url)
|
|
||||||
if (url.hostname === 'youtu.be') {
|
|
||||||
// replace youtu.be to get proper results
|
|
||||||
url.hostname = 'youtube.com'
|
|
||||||
}
|
|
||||||
|
|
||||||
const [meta, embed] = await Promise.all([fetchResource(url), fetchEmbed(url)])
|
const [meta, embed] = await Promise.all([fetchResource(url), fetchEmbed(url)])
|
||||||
const output = mergeWith(meta, embed, (objValue, srcValue) => {
|
const output = mergeWith(meta, embed, (objValue, srcValue) => {
|
||||||
if (isArray(objValue)) {
|
if (isArray(objValue)) {
|
||||||
|
|||||||
@ -972,7 +972,7 @@
|
|||||||
url-regex "~4.1.1"
|
url-regex "~4.1.1"
|
||||||
video-extensions "~1.1.0"
|
video-extensions "~1.1.0"
|
||||||
|
|
||||||
"@metascraper/helpers@^5.6.3", "@metascraper/helpers@^5.6.5":
|
"@metascraper/helpers@^5.6.5":
|
||||||
version "5.6.5"
|
version "5.6.5"
|
||||||
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.6.5.tgz#6f42bd1a8e3243e051e7bb067145125cd6b37e09"
|
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.6.5.tgz#6f42bd1a8e3243e051e7bb067145125cd6b37e09"
|
||||||
integrity sha512-j9qxXqZ9k/uNkABlsVjNN2Z5pVtukDmZMZ0ACsob+m5o8/yo87GvRf/UJfTPtog9vZ/QwkLav5Hhl+10NC7QLw==
|
integrity sha512-j9qxXqZ9k/uNkABlsVjNN2Z5pVtukDmZMZ0ACsob+m5o8/yo87GvRf/UJfTPtog9vZ/QwkLav5Hhl+10NC7QLw==
|
||||||
@ -2814,10 +2814,10 @@ data-urls@^1.0.0:
|
|||||||
whatwg-mimetype "^2.2.0"
|
whatwg-mimetype "^2.2.0"
|
||||||
whatwg-url "^7.0.0"
|
whatwg-url "^7.0.0"
|
||||||
|
|
||||||
date-fns@2.0.0-beta.3:
|
date-fns@2.0.0-beta.4:
|
||||||
version "2.0.0-beta.3"
|
version "2.0.0-beta.4"
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.0.0-beta.3.tgz#2e28f5af945930f774ddd778e184d68227101d55"
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.0.0-beta.4.tgz#3e1bf33a15da69481f81972c4a50aad762a81f2c"
|
||||||
integrity sha512-z5O262BvHPhwUvA1weXH+AZodygnZUcORERw8hjwBUrRPGrAo2e/rjXfC8Ykf1OGJZGDuLnK/WXbEZBIc0exGQ==
|
integrity sha512-xekjYm7ZDBuzePM/GBodhi3hW3P8dd2RbuIOLBjet2E6EGFR82wHTTXCSGuDEoapqlDvsx88ymRsq85lbM7dDw==
|
||||||
|
|
||||||
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
|
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
@ -5828,12 +5828,12 @@ metascraper-lang-detector@^4.8.5:
|
|||||||
franc "~4.0.0"
|
franc "~4.0.0"
|
||||||
iso-639-3 "~1.1.0"
|
iso-639-3 "~1.1.0"
|
||||||
|
|
||||||
metascraper-lang@^5.6.3:
|
metascraper-lang@^5.6.5:
|
||||||
version "5.6.3"
|
version "5.6.5"
|
||||||
resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.6.3.tgz#d2d7a20f4145b0785391fffec629e154737fc942"
|
resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.6.5.tgz#0363514de4bb580f8e571502e7421b2345cd54bf"
|
||||||
integrity sha512-c13zxmREcB/hDXs7MIxio7RNfVsSzGfixk6FrfQQh3fypmiR84SpeZmQR+G/e2X/BDNwpIydJM62R7BayY709Q==
|
integrity sha512-mp9fVytxX9eLGNI16CYGEhBXhG3a0/RtjVqtcngSyeVZl7SKxMyGLrGqDgCuoU6Til/n11ujEnu3wlQfbGclIg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@metascraper/helpers" "^5.6.3"
|
"@metascraper/helpers" "^5.6.5"
|
||||||
|
|
||||||
metascraper-logo@^5.6.5:
|
metascraper-logo@^5.6.5:
|
||||||
version "5.6.5"
|
version "5.6.5"
|
||||||
@ -6143,10 +6143,10 @@ neo4j-graphql-js@^2.6.3:
|
|||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
neo4j-driver "^1.7.3"
|
neo4j-driver "^1.7.3"
|
||||||
|
|
||||||
neode@^0.3.0:
|
neode@^0.3.1:
|
||||||
version "0.3.0"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/neode/-/neode-0.3.0.tgz#a4a41234fac23236db6b589ec2b505ad6e5fd832"
|
resolved "https://registry.yarnpkg.com/neode/-/neode-0.3.1.tgz#d40147bf20d6951b69c9d392fbdd322aeca07816"
|
||||||
integrity sha512-V6uQhap7FDwbeC+mH6JEI352QSou4Ukj7vs/bGZSrVlMZKVS8vs/mbQYXoFdCkmQJuUtJWqO9wmtWg5GjCaNDQ==
|
integrity sha512-SdaJmdjQ3PWOH6W1H8Xgd2CLyJs+BPPXPt0jOVNs7naeQH8nWPP6ixDqI6NWDCxwecTdNl//fpAicB9I6hCwEw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@hapi/joi" "^15.1.0"
|
"@hapi/joi" "^15.1.0"
|
||||||
dotenv "^4.0.0"
|
dotenv "^4.0.0"
|
||||||
|
|||||||
@ -230,7 +230,7 @@ When("I choose {string} as the title of the post", title => {
|
|||||||
|
|
||||||
When("I type in the following text:", text => {
|
When("I type in the following text:", text => {
|
||||||
lastPost.content = text.replace("\n", " ");
|
lastPost.content = text.replace("\n", " ");
|
||||||
cy.get(".ProseMirror").type(lastPost.content);
|
cy.get(".editor .ProseMirror").type(lastPost.content);
|
||||||
});
|
});
|
||||||
|
|
||||||
Then("the post shows up on the landing page at position {int}", index => {
|
Then("the post shows up on the landing page at position {int}", index => {
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
"faker": "Marak/faker.js#master",
|
"faker": "Marak/faker.js#master",
|
||||||
"graphql-request": "^1.8.2",
|
"graphql-request": "^1.8.2",
|
||||||
"neo4j-driver": "^1.7.5",
|
"neo4j-driver": "^1.7.5",
|
||||||
"neode": "^0.3.0",
|
"neode": "^0.3.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"slug": "^1.1.0"
|
"slug": "^1.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,11 @@
|
|||||||
{{ $t('comment.show.more') }}
|
{{ $t('comment.show.more') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isCollapsed" v-html="comment.content" style="padding-left: 40px;" />
|
<content-viewer
|
||||||
|
v-if="!isCollapsed"
|
||||||
|
:content="comment.content"
|
||||||
|
style="padding-left: 40px;"
|
||||||
|
/>
|
||||||
<div style="text-align: right; margin-right: 20px; margin-top: -12px;">
|
<div style="text-align: right; margin-right: 20px; margin-top: -12px;">
|
||||||
<a v-if="!isCollapsed" @click="isCollapsed = !isCollapsed" style="padding-left: 40px; ">
|
<a v-if="!isCollapsed" @click="isCollapsed = !isCollapsed" style="padding-left: 40px; ">
|
||||||
{{ $t('comment.show.less') }}
|
{{ $t('comment.show.less') }}
|
||||||
@ -62,6 +66,7 @@ import gql from 'graphql-tag'
|
|||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
import HcUser from '~/components/User'
|
import HcUser from '~/components/User'
|
||||||
import ContentMenu from '~/components/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu'
|
||||||
|
import ContentViewer from '~/components/Editor/ContentViewer'
|
||||||
import HcEditCommentForm from '~/components/comments/EditCommentForm/EditCommentForm'
|
import HcEditCommentForm from '~/components/comments/EditCommentForm/EditCommentForm'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -74,6 +79,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
HcUser,
|
HcUser,
|
||||||
ContentMenu,
|
ContentMenu,
|
||||||
|
ContentViewer,
|
||||||
HcEditCommentForm,
|
HcEditCommentForm,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
32
webapp/components/Editor/ContentViewer.vue
Normal file
32
webapp/components/Editor/ContentViewer.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<editor-content :editor="editor" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import defaultExtensions from './defaultExtensions.js'
|
||||||
|
import { Editor, EditorContent } from 'tiptap'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContentViewer',
|
||||||
|
components: {
|
||||||
|
EditorContent,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
content: { type: String, default: '' },
|
||||||
|
doc: { type: Object, default: () => {} },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: new Editor({
|
||||||
|
doc: this.doc,
|
||||||
|
content: this.content,
|
||||||
|
editable: false,
|
||||||
|
extensions: defaultExtensions(this),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
132
webapp/components/Editor/Editor.story.js
Normal file
132
webapp/components/Editor/Editor.story.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import { storiesOf } from '@storybook/vue'
|
||||||
|
import { withA11y } from '@storybook/addon-a11y'
|
||||||
|
import HcEditor from '~/components/Editor/Editor.vue'
|
||||||
|
import helpers from '~/storybook/helpers'
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
const embed = {
|
||||||
|
html:
|
||||||
|
'<iframe width="480" height="270" src="https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>',
|
||||||
|
}
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
(app = {}) => {
|
||||||
|
app.$apollo = {
|
||||||
|
mutate: () => {},
|
||||||
|
query: () => {
|
||||||
|
return { data: { embed } }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Vue.prototype.$apollo = app.$apollo
|
||||||
|
return app
|
||||||
|
},
|
||||||
|
]
|
||||||
|
helpers.init({ plugins })
|
||||||
|
|
||||||
|
const users = [{ id: 1, slug: 'peter' }, { id: 2, slug: 'sandra' }, { id: 3, slug: 'jane' }]
|
||||||
|
|
||||||
|
storiesOf('Editor', module)
|
||||||
|
.addDecorator(withA11y)
|
||||||
|
.addDecorator(storyFn => {
|
||||||
|
const ctx = storyFn()
|
||||||
|
return {
|
||||||
|
components: { ctx },
|
||||||
|
template: `
|
||||||
|
<ds-card style="width: 50%; min-width: 500px; margin: 0 auto;">
|
||||||
|
<ctx />
|
||||||
|
</ds-card>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addDecorator(helpers.layout)
|
||||||
|
.add('Empty', () => ({
|
||||||
|
components: { HcEditor },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
users,
|
||||||
|
}),
|
||||||
|
template: `<hc-editor :users="users" />`,
|
||||||
|
}))
|
||||||
|
.add('Basic formatting', () => ({
|
||||||
|
components: { HcEditor },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
users,
|
||||||
|
content: `
|
||||||
|
<h3>Basic formatting</h3>
|
||||||
|
<p>
|
||||||
|
Here is some <em>italic</em>, <b>bold</b> and <u>underline</u> text.
|
||||||
|
<br/>
|
||||||
|
Also do we have some <a href="https://human-connection.org">inline links</a> here.
|
||||||
|
</p>
|
||||||
|
<h3>Heading 3</h3>
|
||||||
|
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
|
||||||
|
<h4>Heading 4</h4>
|
||||||
|
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
|
||||||
|
<h5>Heading 5</h5>
|
||||||
|
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
|
||||||
|
|
||||||
|
<h3>Unordered List</h3>
|
||||||
|
<ul>
|
||||||
|
<li><p>Also some list</p></li>
|
||||||
|
<li><p>with</p></li>
|
||||||
|
<li><p>several</p></li>
|
||||||
|
<li><p>points</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Ordered List</h3>
|
||||||
|
<ol>
|
||||||
|
<li><p>justo</p></li>
|
||||||
|
<li><p>dolores</p></li>
|
||||||
|
<li><p>et ea rebum</p></li>
|
||||||
|
<li><p>kasd gubergren</p></li>
|
||||||
|
</ol>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
template: `<hc-editor :users="users" :value="content" />`,
|
||||||
|
}))
|
||||||
|
.add('@Mentions', () => ({
|
||||||
|
components: { HcEditor },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
users,
|
||||||
|
content: `
|
||||||
|
<p>
|
||||||
|
Here you can mention people like
|
||||||
|
<a class="mention" data-mention-id="2" href="/profile/1" target="_blank" contenteditable="false">@sandra</a> and others.
|
||||||
|
Try it out!
|
||||||
|
</p>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
template: `<hc-editor :users="users" :value="content" />`,
|
||||||
|
}))
|
||||||
|
.add('#Hashtags', () => ({
|
||||||
|
components: { HcEditor },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
users,
|
||||||
|
content: `
|
||||||
|
<p>
|
||||||
|
This text contains <a href="#" class="hashtag">#hashtags</a> for projects like <a href="https://human-connection.org" class="hashtag">#human-connection</a>
|
||||||
|
Try to add more by typing #.
|
||||||
|
</p>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
template: `<hc-editor :users="users" :value="content" />`,
|
||||||
|
}))
|
||||||
|
.add('Embeds', () => ({
|
||||||
|
components: { HcEditor },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
users,
|
||||||
|
content: `
|
||||||
|
<p>
|
||||||
|
The following link should render a youtube video in addition to the link.
|
||||||
|
</p>
|
||||||
|
<a class="embed" href="https://www.youtube.com/watch?v=qkdXAtO40Fo">
|
||||||
|
<em>https://www.youtube.com/watch?v=qkdXAtO40Fo</em>
|
||||||
|
</a>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
template: `<hc-editor :users="users" :value="content" />`,
|
||||||
|
}))
|
||||||
@ -183,30 +183,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import defaultExtensions from './defaultExtensions.js'
|
||||||
import linkify from 'linkify-it'
|
import linkify from 'linkify-it'
|
||||||
import stringHash from 'string-hash'
|
import stringHash from 'string-hash'
|
||||||
import Fuse from 'fuse.js'
|
import Fuse from 'fuse.js'
|
||||||
import tippy from 'tippy.js'
|
import tippy from 'tippy.js'
|
||||||
import { Editor, EditorContent, EditorFloatingMenu, EditorMenuBubble } from 'tiptap'
|
import { Editor, EditorContent, EditorFloatingMenu, EditorMenuBubble } from 'tiptap'
|
||||||
import EventHandler from './plugins/eventHandler.js'
|
import EventHandler from './plugins/eventHandler.js'
|
||||||
import {
|
import { History } from 'tiptap-extensions'
|
||||||
Heading,
|
|
||||||
HardBreak,
|
|
||||||
Blockquote,
|
|
||||||
ListItem,
|
|
||||||
BulletList,
|
|
||||||
OrderedList,
|
|
||||||
HorizontalRule,
|
|
||||||
Placeholder,
|
|
||||||
Bold,
|
|
||||||
Italic,
|
|
||||||
Strike,
|
|
||||||
Underline,
|
|
||||||
Link,
|
|
||||||
History,
|
|
||||||
} from 'tiptap-extensions'
|
|
||||||
import Mention from './nodes/Mention.js'
|
|
||||||
import Hashtag from './nodes/Hashtag.js'
|
import Hashtag from './nodes/Hashtag.js'
|
||||||
|
import Mention from './nodes/Mention.js'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
let throttleInputEvent
|
let throttleInputEvent
|
||||||
@ -389,24 +375,8 @@ export default {
|
|||||||
content: this.value || '',
|
content: this.value || '',
|
||||||
doc: this.doc,
|
doc: this.doc,
|
||||||
extensions: [
|
extensions: [
|
||||||
|
...defaultExtensions(this),
|
||||||
new EventHandler(),
|
new EventHandler(),
|
||||||
new Heading(),
|
|
||||||
new HardBreak(),
|
|
||||||
new Blockquote(),
|
|
||||||
new BulletList(),
|
|
||||||
new OrderedList(),
|
|
||||||
new HorizontalRule(),
|
|
||||||
new Bold(),
|
|
||||||
new Italic(),
|
|
||||||
new Strike(),
|
|
||||||
new Underline(),
|
|
||||||
new Link(),
|
|
||||||
new Heading({ levels: [3, 4] }),
|
|
||||||
new ListItem(),
|
|
||||||
new Placeholder({
|
|
||||||
emptyNodeClass: 'is-empty',
|
|
||||||
emptyNodeText: this.placeholder || this.$t('editor.placeholder'),
|
|
||||||
}),
|
|
||||||
new History(),
|
new History(),
|
||||||
...optionalExtensions,
|
...optionalExtensions,
|
||||||
],
|
],
|
||||||
@ -505,13 +475,11 @@ export default {
|
|||||||
selectItem(item) {
|
selectItem(item) {
|
||||||
const typeAttrs = {
|
const typeAttrs = {
|
||||||
mention: {
|
mention: {
|
||||||
// TODO: use router here
|
id: item.id,
|
||||||
url: `/profile/${item.id}`,
|
|
||||||
label: item.slug,
|
label: item.slug,
|
||||||
},
|
},
|
||||||
hashtag: {
|
hashtag: {
|
||||||
// TODO: Fill up with input hashtag in search field
|
id: item.name,
|
||||||
url: `/search/hashtag/${item.name}`,
|
|
||||||
label: item.name,
|
label: item.name,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
49
webapp/components/Editor/commands/pasteRule.js
Normal file
49
webapp/components/Editor/commands/pasteRule.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Plugin } from 'prosemirror-state'
|
||||||
|
import { Slice, Fragment } from 'prosemirror-model'
|
||||||
|
|
||||||
|
export default function(regexp, type, getAttrs) {
|
||||||
|
const handler = fragment => {
|
||||||
|
const nodes = []
|
||||||
|
|
||||||
|
fragment.forEach(child => {
|
||||||
|
if (child.isText) {
|
||||||
|
const { text } = child
|
||||||
|
let pos = 0
|
||||||
|
let match
|
||||||
|
|
||||||
|
do {
|
||||||
|
match = regexp.exec(text)
|
||||||
|
if (match) {
|
||||||
|
const start = match.index
|
||||||
|
const end = start + match[0].length
|
||||||
|
const attrs = getAttrs instanceof Function ? getAttrs(match[0]) : getAttrs
|
||||||
|
|
||||||
|
if (start > 0) {
|
||||||
|
nodes.push(child.cut(pos, start))
|
||||||
|
}
|
||||||
|
|
||||||
|
// only difference to `pasteRule` of `tiptap-commands`:
|
||||||
|
// we replace the node instead of adding markup
|
||||||
|
nodes.push(type.create(attrs, child.cut(start, end)))
|
||||||
|
|
||||||
|
pos = end
|
||||||
|
}
|
||||||
|
} while (match)
|
||||||
|
|
||||||
|
if (pos < text.length) {
|
||||||
|
nodes.push(child.cut(pos))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodes.push(child.copy(handler(child.content)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Fragment.fromArray(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Plugin({
|
||||||
|
props: {
|
||||||
|
transformPasted: slice => new Slice(handler(slice.content), slice.openStart, slice.openEnd),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
48
webapp/components/Editor/defaultExtensions.js
Normal file
48
webapp/components/Editor/defaultExtensions.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import Embed from '~/components/Editor/nodes/Embed.js'
|
||||||
|
import Link from '~/components/Editor/nodes/Link.js'
|
||||||
|
import Strike from '~/components/Editor/marks/Strike'
|
||||||
|
import Italic from '~/components/Editor/marks/Italic'
|
||||||
|
import Bold from '~/components/Editor/marks/Bold'
|
||||||
|
import EmbedQuery from '~/graphql/EmbedQuery.js'
|
||||||
|
import {
|
||||||
|
Heading,
|
||||||
|
HardBreak,
|
||||||
|
Blockquote,
|
||||||
|
ListItem,
|
||||||
|
BulletList,
|
||||||
|
OrderedList,
|
||||||
|
HorizontalRule,
|
||||||
|
Placeholder,
|
||||||
|
Underline,
|
||||||
|
} from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default function defaultExtensions(component) {
|
||||||
|
const { placeholder, $t, $apollo } = component
|
||||||
|
return [
|
||||||
|
new Heading(),
|
||||||
|
new HardBreak(),
|
||||||
|
new Blockquote(),
|
||||||
|
new BulletList(),
|
||||||
|
new OrderedList(),
|
||||||
|
new HorizontalRule(),
|
||||||
|
new Bold(),
|
||||||
|
new Italic(),
|
||||||
|
new Strike(),
|
||||||
|
new Underline(),
|
||||||
|
new Link(),
|
||||||
|
new Heading({ levels: [3, 4] }),
|
||||||
|
new ListItem(),
|
||||||
|
new Placeholder({
|
||||||
|
emptyNodeClass: 'is-empty',
|
||||||
|
emptyNodeText: placeholder || $t('editor.placeholder'),
|
||||||
|
}),
|
||||||
|
new Embed({
|
||||||
|
onEmbed: async ({ url }) => {
|
||||||
|
const {
|
||||||
|
data: { embed },
|
||||||
|
} = await $apollo.query({ query: EmbedQuery(), variables: { url } })
|
||||||
|
return embed
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
93
webapp/components/Editor/defaultExtensions.spec.js
Normal file
93
webapp/components/Editor/defaultExtensions.spec.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import defaultExtensions from './defaultExtensions.js'
|
||||||
|
import { Editor } from 'tiptap'
|
||||||
|
|
||||||
|
let content
|
||||||
|
let createEditor
|
||||||
|
|
||||||
|
describe('defaultExtensions', () => {
|
||||||
|
describe('editor', () => {
|
||||||
|
createEditor = () => {
|
||||||
|
const componentStub = {
|
||||||
|
placeholder: 'placeholder',
|
||||||
|
$t: jest.fn(),
|
||||||
|
$apollo: {
|
||||||
|
mutate: jest.fn(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return new Editor({
|
||||||
|
content,
|
||||||
|
extensions: [...defaultExtensions(componentStub)],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders', () => {
|
||||||
|
content = ''
|
||||||
|
expect(createEditor().getHTML()).toEqual('<p></p>')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('`content` contains a mentioning', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
content =
|
||||||
|
'<p>This is a post content mentioning <a class="mention" data-mention-id="alicias-id" href="/profile/f0628376-e692-4167-bdb4-d521de5a014f" target="_blank">@alicia-luettgen</a>.</p>'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders mentioning as link', () => {
|
||||||
|
const editor = createEditor()
|
||||||
|
const expected =
|
||||||
|
'<p>This is a post content mentioning <a href="/profile/f0628376-e692-4167-bdb4-d521de5a014f" rel="noopener noreferrer nofollow">@alicia-luettgen</a>.</p>'
|
||||||
|
expect(editor.getHTML()).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('`content` contains a hashtag', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
content =
|
||||||
|
'<p>This is a post content with a hashtag <a class="hashtag" href="/search/hashtag/metoo" target="_blank">#metoo</a>.</p>'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders hashtag as link', () => {
|
||||||
|
const editor = createEditor()
|
||||||
|
const expected =
|
||||||
|
'<p>This is a post content with a hashtag <a href="/search/hashtag/metoo" rel="noopener noreferrer nofollow">#metoo</a>.</p>'
|
||||||
|
expect(editor.getHTML()).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('`content` contains embed code', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
content =
|
||||||
|
'<p>Baby loves cat: </p><a href="https://www.youtube.com/watch?v=qkdXAtO40Fo" class="embed" target="_blank"></a>'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recognizes embed code', () => {
|
||||||
|
const editor = createEditor()
|
||||||
|
const expected = {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
text: 'Baby loves cat:',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'paragraph',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
attrs: {
|
||||||
|
dataEmbedUrl: 'https://www.youtube.com/watch?v=qkdXAtO40Fo',
|
||||||
|
},
|
||||||
|
type: 'embed',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'paragraph',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'doc',
|
||||||
|
}
|
||||||
|
expect(editor.getJSON()).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
7
webapp/components/Editor/marks/Bold.js
Normal file
7
webapp/components/Editor/marks/Bold.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Bold as TipTapBold } from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default class Bold extends TipTapBold {
|
||||||
|
pasteRules() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
7
webapp/components/Editor/marks/Italic.js
Normal file
7
webapp/components/Editor/marks/Italic.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Italic as TipTapItalic } from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default class Italic extends TipTapItalic {
|
||||||
|
pasteRules() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
7
webapp/components/Editor/marks/Strike.js
Normal file
7
webapp/components/Editor/marks/Strike.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Strike as TipTapStrike } from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default class Strike extends TipTapStrike {
|
||||||
|
pasteRules() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
97
webapp/components/Editor/nodes/Embed.js
Normal file
97
webapp/components/Editor/nodes/Embed.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { Node } from 'tiptap'
|
||||||
|
import pasteRule from '../commands/pasteRule'
|
||||||
|
import { compileToFunctions } from 'vue-template-compiler'
|
||||||
|
|
||||||
|
const template = `
|
||||||
|
<a class="embed" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
|
||||||
|
<div v-if="embedHtml" v-html="embedHtml" />
|
||||||
|
<em> {{ dataEmbedUrl }} </em>
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
const compiledTemplate = compileToFunctions(template)
|
||||||
|
|
||||||
|
export default class Embed extends Node {
|
||||||
|
get name() {
|
||||||
|
return 'embed'
|
||||||
|
}
|
||||||
|
|
||||||
|
get defaultOptions() {
|
||||||
|
return {
|
||||||
|
onEmbed: () => ({}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pasteRules({ type, schema }) {
|
||||||
|
return [
|
||||||
|
pasteRule(
|
||||||
|
// source: https://stackoverflow.com/a/3809435
|
||||||
|
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g,
|
||||||
|
type,
|
||||||
|
url => ({ dataEmbedUrl: url }),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
get schema() {
|
||||||
|
return {
|
||||||
|
attrs: {
|
||||||
|
dataEmbedUrl: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
group: 'inline',
|
||||||
|
inline: true,
|
||||||
|
parseDOM: [
|
||||||
|
{
|
||||||
|
tag: 'a[href].embed',
|
||||||
|
getAttrs: dom => ({
|
||||||
|
dataEmbedUrl: dom.getAttribute('href'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toDOM: node => [
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
href: node.attrs.dataEmbedUrl,
|
||||||
|
class: 'embed',
|
||||||
|
target: '_blank',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get view() {
|
||||||
|
return {
|
||||||
|
props: ['node', 'updateAttrs', 'options'],
|
||||||
|
data: () => ({
|
||||||
|
embedData: {},
|
||||||
|
}),
|
||||||
|
async created() {
|
||||||
|
if (!this.options) return {}
|
||||||
|
this.embedData = await this.options.onEmbed({ url: this.dataEmbedUrl })
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
embedClass() {
|
||||||
|
return this.embedHtml ? 'embed' : ''
|
||||||
|
},
|
||||||
|
embedHtml() {
|
||||||
|
const { html = '' } = this.embedData
|
||||||
|
return html
|
||||||
|
},
|
||||||
|
dataEmbedUrl: {
|
||||||
|
get() {
|
||||||
|
return this.node.attrs.dataEmbedUrl
|
||||||
|
},
|
||||||
|
set(dataEmbedUrl) {
|
||||||
|
this.updateAttrs({
|
||||||
|
dataEmbedUrl,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
return compiledTemplate.render.call(this, createElement)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
webapp/components/Editor/nodes/Embed.spec.js
Normal file
66
webapp/components/Editor/nodes/Embed.spec.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { shallowMount } from '@vue/test-utils'
|
||||||
|
import Embed from './Embed'
|
||||||
|
|
||||||
|
let Wrapper
|
||||||
|
let propsData
|
||||||
|
const someUrl = 'https://www.youtube.com/watch?v=qkdXAtO40Fo'
|
||||||
|
|
||||||
|
describe('Embed.vue', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = {}
|
||||||
|
const component = new Embed()
|
||||||
|
Wrapper = ({ mocks, propsData }) => {
|
||||||
|
return shallowMount(component.view, { propsData })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders anchor', () => {
|
||||||
|
propsData = {
|
||||||
|
node: { attrs: { href: someUrl } },
|
||||||
|
}
|
||||||
|
expect(Wrapper({ propsData }).is('a')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a href', () => {
|
||||||
|
describe('onEmbed returned embed data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData.options = {
|
||||||
|
onEmbed: () => ({
|
||||||
|
type: 'video',
|
||||||
|
title: 'Baby Loves Cat',
|
||||||
|
author: 'Merkley Family',
|
||||||
|
publisher: 'YouTube',
|
||||||
|
date: '2015-08-16T00:00:00.000Z',
|
||||||
|
description:
|
||||||
|
'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
|
||||||
|
url: someUrl,
|
||||||
|
image: 'https://i.ytimg.com/vi/qkdXAtO40Fo/maxresdefault.jpg',
|
||||||
|
audio: null,
|
||||||
|
video: null,
|
||||||
|
lang: 'de',
|
||||||
|
sources: ['resource', 'oembed'],
|
||||||
|
html:
|
||||||
|
'<iframe width="480" height="270" src="https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>',
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the given html code', async () => {
|
||||||
|
propsData.node = { attrs: { href: 'https://www.youtube.com/watch?v=qkdXAtO40Fo' } }
|
||||||
|
const wrapper = Wrapper({ propsData })
|
||||||
|
await wrapper.html()
|
||||||
|
expect(wrapper.find('div iframe').attributes('src')).toEqual(
|
||||||
|
'https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('without embedded html but some meta data instead', () => {
|
||||||
|
it.todo('renders description and link')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('without any meta data', () => {
|
||||||
|
it.todo('renders a link without `embed` class')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -18,27 +18,24 @@ export default class Hashtag extends TipTapMention {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get schema() {
|
get schema() {
|
||||||
const patchedSchema = super.schema
|
return {
|
||||||
|
...super.schema,
|
||||||
patchedSchema.attrs = {
|
toDOM: node => {
|
||||||
url: {},
|
return [
|
||||||
label: {},
|
'a',
|
||||||
|
{
|
||||||
|
class: this.options.mentionClass,
|
||||||
|
href: `/search/hashtag/${node.attrs.id}`,
|
||||||
|
'data-hashtag-id': node.attrs.id,
|
||||||
|
target: '_blank',
|
||||||
|
},
|
||||||
|
`${this.options.matcher.char}${node.attrs.label}`,
|
||||||
|
]
|
||||||
|
},
|
||||||
|
parseDOM: [
|
||||||
|
// simply don't parse mentions from html
|
||||||
|
// just treat them as normal links
|
||||||
|
],
|
||||||
}
|
}
|
||||||
patchedSchema.toDOM = node => {
|
|
||||||
return [
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
class: this.options.mentionClass,
|
|
||||||
href: node.attrs.url,
|
|
||||||
target: '_blank',
|
|
||||||
// contenteditable: 'true',
|
|
||||||
},
|
|
||||||
`${this.options.matcher.char}${node.attrs.label}`,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
patchedSchema.parseDOM = [
|
|
||||||
// this is not implemented
|
|
||||||
]
|
|
||||||
return patchedSchema
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
webapp/components/Editor/nodes/Link.js
Normal file
34
webapp/components/Editor/nodes/Link.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Link as TipTapLink } from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default class Link extends TipTapLink {
|
||||||
|
pasteRules({ type }) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
get schema() {
|
||||||
|
return {
|
||||||
|
attrs: {
|
||||||
|
href: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inclusive: false,
|
||||||
|
parseDOM: [
|
||||||
|
{
|
||||||
|
tag: 'a[href]:not(.embed)', // do not trigger on embed links
|
||||||
|
getAttrs: dom => ({
|
||||||
|
href: dom.getAttribute('href'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toDOM: node => [
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
...node.attrs,
|
||||||
|
rel: 'noopener noreferrer nofollow',
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,26 +6,24 @@ export default class Mention extends TipTapMention {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get schema() {
|
get schema() {
|
||||||
const patchedSchema = super.schema
|
return {
|
||||||
|
...super.schema,
|
||||||
patchedSchema.attrs = {
|
toDOM: node => {
|
||||||
url: {},
|
return [
|
||||||
label: {},
|
'a',
|
||||||
|
{
|
||||||
|
class: this.options.mentionClass,
|
||||||
|
href: `/profile/${node.attrs.id}`,
|
||||||
|
'data-mention-id': node.attrs.id,
|
||||||
|
target: '_blank',
|
||||||
|
},
|
||||||
|
`${this.options.matcher.char}${node.attrs.label}`,
|
||||||
|
]
|
||||||
|
},
|
||||||
|
parseDOM: [
|
||||||
|
// simply don't parse mentions from html
|
||||||
|
// just treat them as normal links
|
||||||
|
],
|
||||||
}
|
}
|
||||||
patchedSchema.toDOM = node => {
|
|
||||||
return [
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
class: this.options.mentionClass,
|
|
||||||
href: node.attrs.url,
|
|
||||||
target: '_blank',
|
|
||||||
},
|
|
||||||
`${this.options.matcher.char}${node.attrs.label}`,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
patchedSchema.parseDOM = [
|
|
||||||
// this is not implemented
|
|
||||||
]
|
|
||||||
return patchedSchema
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,13 +28,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConfirmModal',
|
name: 'ConfirmModal',
|
||||||
components: {
|
|
||||||
SweetalertIcon,
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
name: { type: String, default: '' },
|
name: { type: String, default: '' },
|
||||||
type: { type: String, required: true },
|
type: { type: String, required: true },
|
||||||
|
|||||||
@ -27,13 +27,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ReportModal',
|
name: 'ReportModal',
|
||||||
components: {
|
|
||||||
SweetalertIcon,
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
name: { type: String, default: '' },
|
name: { type: String, default: '' },
|
||||||
type: { type: String, required: true },
|
type: { type: String, required: true },
|
||||||
|
|||||||
@ -54,12 +54,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import PasswordStrength from '../Password/Strength'
|
import PasswordStrength from '../Password/Strength'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SweetalertIcon,
|
|
||||||
PasswordStrength,
|
PasswordStrength,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@ -48,12 +48,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
|
||||||
SweetalertIcon,
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
formData: {
|
formData: {
|
||||||
|
|||||||
78
webapp/components/PostCard/PostCard.story.js
Normal file
78
webapp/components/PostCard/PostCard.story.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { storiesOf } from '@storybook/vue'
|
||||||
|
import { withA11y } from '@storybook/addon-a11y'
|
||||||
|
import HcPostCard from '~/components/PostCard'
|
||||||
|
import helpers from '~/storybook/helpers'
|
||||||
|
|
||||||
|
helpers.init()
|
||||||
|
|
||||||
|
const post = {
|
||||||
|
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
|
||||||
|
title: 'Very nice Post Title',
|
||||||
|
contentExcerpt: '<p>My post content</p>',
|
||||||
|
createdAt: '2019-06-24T22:08:59.304Z',
|
||||||
|
disabled: false,
|
||||||
|
deleted: false,
|
||||||
|
slug: 'very-nice-post-title',
|
||||||
|
image: null,
|
||||||
|
author: {
|
||||||
|
id: 'u3',
|
||||||
|
avatar:
|
||||||
|
'https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/db/dbc9e03ebcc384b920c31542af2d27dd8eea9dc2_full.jpg',
|
||||||
|
slug: 'jenny-rostock',
|
||||||
|
name: 'Rainer Unsinn',
|
||||||
|
disabled: false,
|
||||||
|
deleted: false,
|
||||||
|
contributionsCount: 25,
|
||||||
|
shoutedCount: 5,
|
||||||
|
commentsCount: 39,
|
||||||
|
followedByCount: 2,
|
||||||
|
followedByCurrentUser: true,
|
||||||
|
location: null,
|
||||||
|
badges: [
|
||||||
|
{
|
||||||
|
id: 'b4',
|
||||||
|
key: 'indiegogo_en_bear',
|
||||||
|
icon: '/img/badges/indiegogo_en_bear.svg',
|
||||||
|
__typename: 'Badge',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__typename: 'User',
|
||||||
|
},
|
||||||
|
commentsCount: 12,
|
||||||
|
categories: [],
|
||||||
|
shoutedCount: 421,
|
||||||
|
__typename: 'Post',
|
||||||
|
}
|
||||||
|
|
||||||
|
storiesOf('Post Card', module)
|
||||||
|
.addDecorator(withA11y)
|
||||||
|
.addDecorator(helpers.layout)
|
||||||
|
.add('without image', () => ({
|
||||||
|
components: { HcPostCard },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
post,
|
||||||
|
}),
|
||||||
|
template: `
|
||||||
|
<hc-post-card
|
||||||
|
:post="post"
|
||||||
|
:width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }"
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
.add('with image', () => ({
|
||||||
|
components: { HcPostCard },
|
||||||
|
store: helpers.store,
|
||||||
|
data: () => ({
|
||||||
|
post: {
|
||||||
|
...post,
|
||||||
|
image: 'https://unsplash.com/photos/R4y_E5ZQDPg/download',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
template: `
|
||||||
|
<hc-post-card
|
||||||
|
:post="post"
|
||||||
|
:width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }"
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
@ -71,7 +71,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import PasswordStrength from '../Password/Strength'
|
import PasswordStrength from '../Password/Strength'
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||||
|
|
||||||
export const SignupVerificationMutation = gql`
|
export const SignupVerificationMutation = gql`
|
||||||
@ -86,7 +85,6 @@ export const SignupVerificationMutation = gql`
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PasswordStrength,
|
PasswordStrength,
|
||||||
SweetalertIcon,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const passwordForm = PasswordForm({ translate: this.$t })
|
const passwordForm = PasswordForm({ translate: this.$t })
|
||||||
|
|||||||
@ -56,7 +56,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
|
||||||
|
|
||||||
export const SignupMutation = gql`
|
export const SignupMutation = gql`
|
||||||
mutation($email: String!) {
|
mutation($email: String!) {
|
||||||
@ -73,9 +72,6 @@ export const SignupByInvitationMutation = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
export default {
|
export default {
|
||||||
components: {
|
|
||||||
SweetalertIcon,
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
token: { type: String, default: null },
|
token: { type: String, default: null },
|
||||||
},
|
},
|
||||||
|
|||||||
23
webapp/graphql/EmbedQuery.js
Normal file
23
webapp/graphql/EmbedQuery.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
return gql`
|
||||||
|
query($url: String!) {
|
||||||
|
embed(url: $url) {
|
||||||
|
type
|
||||||
|
title
|
||||||
|
author
|
||||||
|
publisher
|
||||||
|
date
|
||||||
|
description
|
||||||
|
url
|
||||||
|
image
|
||||||
|
audio
|
||||||
|
video
|
||||||
|
lang
|
||||||
|
sources
|
||||||
|
html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@
|
|||||||
:width="{ base: '85%', sm: '85%', md: '50%', lg: '50%' }"
|
:width="{ base: '85%', sm: '85%', md: '50%', lg: '50%' }"
|
||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
>
|
>
|
||||||
<div id="nav-search-box">
|
<div id="nav-search-box" v-if="isLoggedIn">
|
||||||
<search-input
|
<search-input
|
||||||
id="nav-search"
|
id="nav-search"
|
||||||
:delay="300"
|
:delay="300"
|
||||||
@ -33,6 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
|
v-if="isLoggedIn"
|
||||||
:width="{ base: '15%', sm: '15%', md: '10%', lg: '10%' }"
|
:width="{ base: '15%', sm: '15%', md: '10%', lg: '10%' }"
|
||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
>
|
>
|
||||||
@ -116,7 +117,7 @@
|
|||||||
</ds-container>
|
</ds-container>
|
||||||
</div>
|
</div>
|
||||||
<ds-container style="word-break: break-all">
|
<ds-container style="word-break: break-all">
|
||||||
<div class="main-container" :width="{ base: '100%', md: '96%' }">
|
<div class="main-container">
|
||||||
<nuxt />
|
<nuxt />
|
||||||
</div>
|
</div>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
@ -125,9 +126,11 @@
|
|||||||
-
|
-
|
||||||
<nuxt-link to="/imprint">{{ $t('site.imprint') }}</nuxt-link>
|
<nuxt-link to="/imprint">{{ $t('site.imprint') }}</nuxt-link>
|
||||||
‑
|
‑
|
||||||
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAc') }}</nuxt-link>
|
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAndConditions') }}</nuxt-link>
|
||||||
‑
|
‑
|
||||||
<nuxt-link to="/privacy">{{ $t('site.privacy') }}</nuxt-link>
|
<nuxt-link to="/code-of-conduct">{{ $t('site.code-of-conduct') }}</nuxt-link>
|
||||||
|
‑
|
||||||
|
<nuxt-link to="/data-privacy">{{ $t('site.data-privacy') }}</nuxt-link>
|
||||||
‑
|
‑
|
||||||
<nuxt-link to="/changelog">{{ $t('site.changelog') }}</nuxt-link>
|
<nuxt-link to="/changelog">{{ $t('site.changelog') }}</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
@ -149,7 +152,6 @@ import HcAvatar from '~/components/Avatar/Avatar.vue'
|
|||||||
import seo from '~/mixins/seo'
|
import seo from '~/mixins/seo'
|
||||||
import FilterPosts from '~/components/FilterPosts/FilterPosts.vue'
|
import FilterPosts from '~/components/FilterPosts/FilterPosts.vue'
|
||||||
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
@ -266,47 +268,38 @@ export default {
|
|||||||
align-self: center;
|
align-self: center;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-container {
|
.main-container {
|
||||||
padding-top: 6rem;
|
padding-top: 6rem;
|
||||||
padding-bottom: 5rem;
|
padding-bottom: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-navigation {
|
.main-navigation {
|
||||||
a {
|
a {
|
||||||
color: $text-color-soft;
|
color: $text-color-soft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-navigation-right {
|
.main-navigation-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-navigation-right .desktop-view {
|
.main-navigation-right .desktop-view {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-menu {
|
.avatar-menu {
|
||||||
margin: 2px 0px 0px 5px;
|
margin: 2px 0px 0px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-menu-trigger {
|
.avatar-menu-trigger {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: $space-xx-small;
|
padding-left: $space-xx-small;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-menu-popover {
|
.avatar-menu-popover {
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
color: $color-neutral-90;
|
color: $color-neutral-90;
|
||||||
background-color: $color-neutral-90;
|
background-color: $color-neutral-90;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-link {
|
.logout-link {
|
||||||
margin-left: -$space-small;
|
margin-left: -$space-small;
|
||||||
margin-right: -$space-small;
|
margin-right: -$space-small;
|
||||||
@ -315,43 +308,35 @@ export default {
|
|||||||
padding: $space-x-small $space-small;
|
padding: $space-x-small $space-small;
|
||||||
// subtract menu border with from padding
|
// subtract menu border with from padding
|
||||||
padding-left: $space-small - 2;
|
padding-left: $space-small - 2;
|
||||||
|
|
||||||
color: $text-color-base;
|
color: $text-color-base;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $text-color-link-active;
|
color: $text-color-link-active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
margin-left: -$space-small;
|
margin-left: -$space-small;
|
||||||
margin-right: -$space-small;
|
margin-right: -$space-small;
|
||||||
margin-top: -$space-xx-small;
|
margin-top: -$space-xx-small;
|
||||||
margin-bottom: -$space-xx-small;
|
margin-bottom: -$space-xx-small;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: 960px) {
|
@media only screen and (min-width: 960px) {
|
||||||
.mobile-hamburger-menu {
|
.mobile-hamburger-menu {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 960px) {
|
@media only screen and (max-width: 960px) {
|
||||||
#nav-search-box,
|
#nav-search-box,
|
||||||
.main-navigation-right {
|
.main-navigation-right {
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide-mobile-menu {
|
.hide-mobile-menu {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ds-footer {
|
.ds-footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@ -11,8 +11,8 @@
|
|||||||
"site": {
|
"site": {
|
||||||
"made": "Mit ❤ gemacht",
|
"made": "Mit ❤ gemacht",
|
||||||
"imprint": "Impressum",
|
"imprint": "Impressum",
|
||||||
"termsAc": "Nutzungsbedingungen",
|
"data-privacy": "Datenschutz",
|
||||||
"privacy": "Datenschutz",
|
"termsAndConditions": "Nutzungsbedingungen",
|
||||||
"changelog": "Änderungen & Verlauf",
|
"changelog": "Änderungen & Verlauf",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"tribunal": "Registergericht",
|
"tribunal": "Registergericht",
|
||||||
@ -21,7 +21,8 @@
|
|||||||
"taxident": "Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz (Deutschland)",
|
"taxident": "Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz (Deutschland)",
|
||||||
"responsible": "Verantwortlicher gemäß § 55 Abs. 2 RStV ",
|
"responsible": "Verantwortlicher gemäß § 55 Abs. 2 RStV ",
|
||||||
"bank": "Bankverbindung",
|
"bank": "Bankverbindung",
|
||||||
"germany": "Deutschland"
|
"germany": "Deutschland",
|
||||||
|
"code-of-conduct": "Verhaltenscodex"
|
||||||
},
|
},
|
||||||
"sorting": {
|
"sorting": {
|
||||||
"newest": "Neuste",
|
"newest": "Neuste",
|
||||||
@ -55,6 +56,7 @@
|
|||||||
"title": "Mach mit bei Human Connection!",
|
"title": "Mach mit bei Human Connection!",
|
||||||
"form": {
|
"form": {
|
||||||
"description": "Um loszulegen, gib deine E-Mail Adresse ein:",
|
"description": "Um loszulegen, gib deine E-Mail Adresse ein:",
|
||||||
|
"invitation-code": "Dein Einladungscode lautet: <b>{code}</b>",
|
||||||
"errors": {
|
"errors": {
|
||||||
"email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail Adresse!",
|
"email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail Adresse!",
|
||||||
"invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
|
"invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
|
||||||
@ -252,7 +254,8 @@
|
|||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"submit": "Kommentiere",
|
"submit": "Kommentiere",
|
||||||
"submitted": "Kommentar gesendet"
|
"submitted": "Kommentar Gesendet",
|
||||||
|
"updated": "Änderungen gespeichert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
@ -358,17 +361,20 @@
|
|||||||
"user": {
|
"user": {
|
||||||
"title": "Nutzer melden",
|
"title": "Nutzer melden",
|
||||||
"type": "Nutzer",
|
"type": "Nutzer",
|
||||||
"message": "Bist du sicher, dass du den Nutzer \"<b>{name}</b>\" melden möchtest?"
|
"message": "Bist du sicher, dass du den Nutzer \"<b>{name}</b>\" melden möchtest?",
|
||||||
|
"error": "Du hast den Benutzer bereits gemeldet!"
|
||||||
},
|
},
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"title": "Beitrag melden",
|
"title": "Beitrag melden",
|
||||||
"type": "Beitrag",
|
"type": "Beitrag",
|
||||||
"message": "Bist du sicher, dass du den Beitrag \"<b>{name}</b>\" melden möchtest?"
|
"message": "Bist du sicher, dass du den Beitrag \"<b>{name}</b>\" melden möchtest?",
|
||||||
|
"error": "Du hast den Beitrag bereits gemeldet!"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Kommentar melden",
|
"title": "Kommentar melden",
|
||||||
"type": "Kommentar",
|
"type": "Kommentar",
|
||||||
"message": "Bist du sicher, dass du den Kommentar von \"<b>{name}</b>\" melden möchtest?"
|
"message": "Bist du sicher, dass du den Kommentar von \"<b>{name}</b>\" melden möchtest?",
|
||||||
|
"error": "Du hast den Kommentar bereits gemeldet!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"followButton": {
|
"followButton": {
|
||||||
@ -378,7 +384,6 @@
|
|||||||
"shoutButton": {
|
"shoutButton": {
|
||||||
"shouted": "empfohlen"
|
"shouted": "empfohlen"
|
||||||
},
|
},
|
||||||
|
|
||||||
"release": {
|
"release": {
|
||||||
"submit": "freigeben",
|
"submit": "freigeben",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
@ -393,7 +398,7 @@
|
|||||||
"title": "Beitrag freigeben",
|
"title": "Beitrag freigeben",
|
||||||
"type": "Beitrag",
|
"type": "Beitrag",
|
||||||
"message": "Bist du sicher, dass du den Beitrag \"<b>{name}</b>\" freigeben möchtest?",
|
"message": "Bist du sicher, dass du den Beitrag \"<b>{name}</b>\" freigeben möchtest?",
|
||||||
"error": " Den Beitrag hast du schon gemeldet!"
|
"error": "Den Beitrag hast du schon gemeldet!"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Kommentar freigeben",
|
"title": "Kommentar freigeben",
|
||||||
@ -417,7 +422,119 @@
|
|||||||
"infoSelectedNoOfMaxCategories": "{chosen} von {max} Kategorien ausgewählt"
|
"infoSelectedNoOfMaxCategories": "{chosen} von {max} Kategorien ausgewählt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terms": {
|
"changelog": {
|
||||||
"text": "<div ><ol><li><strong>UNFALLGEFAHR: </strong>Das ist eine Testversion! Alle Daten, Dein Profil und die Server können jederzeit komplett vernichtet, verloren, verbrannt und vielleicht auch in der Nähe von Alpha Centauri synchronisiert werden. Die Benutzung läuft auf eigene Gefahr. Mit kommerziellen Nebenwirkungen ist jedoch nicht zu rechnen.</li><br><li><strong>DU UND DEINE DATEN: </strong>Bitte beachte, dass wir die Inhalte der Alphaversion zu Werbezwecken, Webpräsentationen usw. verwenden, aber wir glauben, dass das auch in Deinem Interesse ist. Am besten keinen Nachnamen eingeben und bei noch mehr Datensparsamkeit ein Profilfoto ohne Identität verwenden. Mehr in unserer <a href='/pages/privacy' target='_blank'>Datenschutzerklärung</a>.</li><br><li><strong>BAUSTELLEN: </strong>Das ist immer noch eine Testversion. Wenn etwas nicht funktioniert, blockiert, irritiert, falsch angezeigt, verbogen oder nicht anklickbar ist, bitten wir dies zu entschuldigen. Fehler, Käfer und Bugs bitte melden! <a href='http://localhost:3000/%22https://human-connection.org/alpha/#bugreport%5C%22' target='_blank'>https://human-connection.org/support</a></li><br><li><strong>VERHALTENSCODEX</strong>: Die Verhaltensregeln dienen als Leitsätze für den persönlichen Auftritt und den Umgang untereinander. Wer als Nutzer im Human Connection Netzwerk aktiv ist, Beiträge verfasst, kommentiert oder mit anderen Nutzern, auch außerhalb des Netzwerkes, Kontakt aufnimmt, erkennt diese Verhaltensregeln als verbindlich an: <a href='https://alpha.human-connection.org/pages/code-of-conduct' target='_blank'>https://alpha.human-connection.org/pages/code-of-conduct</a></li><br><li><strong>MODERATION: </strong>Solange kein Community-Moderationssystem lauffähig ist, entscheidet ein Regenbogen-Einhorn darüber, ob Du körperlich und psychisch stabil genug bist, unsere Testversion zu bedienen. Das Einhorn kann Dich jederzeit von der Alpha entfernen. Also sei nett und lass Regenbogenfutter da!</li><br><li><strong>FAIRNESS: </strong>Sollte Dir die Alphaversion unseres Netzwerks wider Erwarten, egal aus welchen Gründen, nicht gefallen, überweisen wir Dir Deine gespendeten Monatsbeiträge innerhalb der ersten 2 Monate gerne zurück. Einfach Mail an: <a href='mailto:info@human-connection.org' target='_blank'>info@human-connection.org </a><strong>Achtung: Viele Funktionen werden erst nach und nach eingebaut. </strong></li><br><li><strong>FRAGEN?</strong> Die Termine und Links zu den Zoom-Räumen findest Du hier: <a href='http://localhost:3000/%22https://human-connection.org/events-und-news//%22' target='_blank'>https://human-connection.org/veranstaltungen/</a></li><br><li><strong>VON MENSCHEN FÜR MENSCHEN: </strong>Bitte hilf uns weitere monatlichen Spender für Human Connection zu bekommen, damit das Netzwerk so schnell wie möglich offiziell an den Start gehen kann. <a href='http://localhost:3000/%22https://human-connection.org/alpha/#bugreport%5C%22' target='_blank'>https://human-connection.org</a></li></ol><p>Jetzt aber viel Spaß mit der Alpha von Human Connection! Für den ersten Weltfrieden. ♥︎</p><br><p><strong>Herzlichst,</strong></p><p><strong>Euer Human Connection Team</strong></p></div>"
|
"24": "Dialog zum Ändern des Passwortes wurde hinzugefügt.",
|
||||||
|
"23": "Ein Editor zum Schreiben von Beiträgen wurde hinzugefügt.",
|
||||||
|
"22": "Ein Dialog zum Ausblenden von Posts und Kommentaren, die gegen die Nutzungsbedingungen verstoßen wurde für die Nutzung durch Moderatoren hinzugefügt.",
|
||||||
|
"21": "Der \"Empfehlen\" Knopf mit dem Megafon wurde der Artikelansicht hinzugefügt.",
|
||||||
|
"20": "Das automatische Ausrollen der programmierten Software wurde repariert, so dass neue Features immer gleich getestet werden können.",
|
||||||
|
"19": "Alle Software-Repositories wurden in ein großes vereinigt, damit alle gegenseitigen Abhängigkeiten klar sind und durch einen übergreifenden Versionsstand aneinander gekoppelt sind.",
|
||||||
|
"18": "Der Import der Inhalte der heutigen Alpha-Daten in die zukünftige Nitro-Version wurde getestet und automatisiert. Dabei wurden nur Testdaten verwendet.",
|
||||||
|
"17": "Das Webinterface der Nitro wurde hinsichtlich der korrekten Anzeige auf Mobilgeräten wie Handys und Tablets getestet.",
|
||||||
|
"16": "Eine Schaltfläche zum Melden von Inhalten, die den Nutzungsrichtlinien widersprechen, wurde hinzugefügt.",
|
||||||
|
"15": "Eine Moderationswerkzeug, in welchem alle gemeldeten Beiträge für Moderatoren angezeigt werden, wurde hinzugefügt.",
|
||||||
|
"14": "Ein Fehler bei der Benutzer-Authentifizierung wurde behoben, Eingabemöglichkeit von Land, Region und Stadt im 'Über-mich'-Feld in den User-Profilen.",
|
||||||
|
"13": "Einstellungsmöglichkeit der Sprache für Benutzerinterface und Inhalte in der Nitro, so, wie in der Alpha.",
|
||||||
|
"12": "Integration des Nuxt-i18n-Toolkits für Sprachunterstützung bei serverseitig gerenderten Webapps.",
|
||||||
|
"11": "Integration der Lokalise.co-Pipeline für Übersetzungen.",
|
||||||
|
"10": "Verwendete Toolkits und Frameworks auf den neuesten Stand upgedatet.",
|
||||||
|
"9": "[laufend] Icons für Admin-Interfae der Kategorien und Tags hinzugefügt und Anzahl, wie viele User einen Tag benutzen.",
|
||||||
|
"8": "Ersetzen der eingesetzten eslint-Version für die Code-Qualität durch die Aktuelle.",
|
||||||
|
"7": "[laufend] Implementierung der Blacklist auf der Nitro zum Ausfiltern von Inhalten nicht gewünschter User.",
|
||||||
|
"6": "Programmierung einer Funktionalität, dass später User, die keine Spender sind, um eine Spende gebeten werden können, um die Weiterentwicklung besser zu unterstützen",
|
||||||
|
"5": "Programmierung einer Datenbankabfrage, welche User einen nicht abgeschlossenen Anmeldungprozess haben, um diese zwecks Hilfestellung kontaktieren zu können",
|
||||||
|
"4": "Einführung eines Versions-Schemas in der Netzwerk-Anwendung um in der laufenden Anwendung die jeweilige Versionerkennen zu können",
|
||||||
|
"3": "Login für die Nitro-Version mit einem 'aufgehübschten' Anmeldedialog.",
|
||||||
|
"2": "Umstellung der Projektplanung auf Zenhub",
|
||||||
|
"1": "Einführung von Scrum als Vorgehensweise für das Projektmanagement",
|
||||||
|
"0": "Start der Arbeit an der \"Nitro\". Dabei wird die Datenbank und die Serverschnittstelle ausgetauscht:"
|
||||||
|
},
|
||||||
|
"code-of-conduct": {
|
||||||
|
"subheader": "für das Soziale Netzwerk der Human Connection gGmbH",
|
||||||
|
"preamble": {
|
||||||
|
"title": "Präambel",
|
||||||
|
"description": "Human Connection ist ein gemeinnütziges soziales Wissens- und Aktionsnetzwerk der nächsten Generation. Von Menschen – für Menschen. Open Source, fair und transparent. Für positiven lokalen und globalen Wandel in allen Lebensbereichen. Wir gestalten den öffentlichen Austausch von Wissen, Ideen und Projekten völlig neu. Die Funktionen von Human Connection bringen die Menschen zusammen – offline und online – so dass wir die Welt zu einem besseren Ort machen können."
|
||||||
|
},
|
||||||
|
"purpose": {
|
||||||
|
"title": "Zweck",
|
||||||
|
"description": "Mit diesen Verhaltensregeln regeln wir die wesentlichen Grundsätze für das Verhalten in unserem Sozialen Netzwerk. Dabei ist die Menschenrechtscharta der Vereinten Nationen unsere Orientierung und bildet das Herz unseres Werteverständnisses. Die Verhaltensregeln dienen als Leitsätze für den persönlichen Auftritt und den Umgang untereinander. Wer als Nutzer im Human Connection Netzwerk aktiv ist, Beiträge verfasst, kommentiert oder mit anderen Nutzern, auch außerhalb des Netzwerkes, Kontakt aufnimmt, erkennt diese Verhaltensregeln als verbindlich an."
|
||||||
|
},
|
||||||
|
|
||||||
|
"expected-behaviour": {
|
||||||
|
"title": "Erwartetes Verhalten",
|
||||||
|
"description": "Die folgenden Verhaltensweisen werden von allen Community-Mitgliedern erwartet und gefordert:",
|
||||||
|
"list": {
|
||||||
|
"0": "Sei rücksichtsvoll und respektvoll bei dem was Du schreibst und tust.",
|
||||||
|
"1": "Versuche auf andere zuzugehen, bevor ein Konflikt entsteht.",
|
||||||
|
"2": "Vermeide erniedrigende, diskriminierende oder belästigende Verhaltensweisen und Ausdrücke.",
|
||||||
|
"3": "Gehe achtsam mit Deiner Umgebung um. Informiere den Support bei gefährlichen Situationen, wenn eine Person in Not ist oder bei Verstößen gegen diesen Verhaltenskodex, auch wenn sie unbedeutend erscheinen."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unacceptable-behaviour": {
|
||||||
|
"title": "Nichtakzeptables Verhalten",
|
||||||
|
"description": "Die folgenden Verhaltensweisen sind in unserer Community inakzeptabel:",
|
||||||
|
"list": {
|
||||||
|
"0": "Diskriminierende Beiträge, Kommentare, Äußerungen oder Beleidigungen, insbesondere solche, die sich auf Geschlecht, sexuelle Orientierung, Rasse, Religion, politische oder weltanschauliche Ausrichtung oder Behinderung beziehen.",
|
||||||
|
"1": "Das Posten oder Verlinken eindeutig pornografischen Materials.",
|
||||||
|
"2": "Verherrlichung oder Verharmlosung grausamer oder unmenschlicher Gewalttätigkeiten.",
|
||||||
|
"3": "Das Veröffentlichen von personenbezogenen Daten anderer ohne deren Einverständnis oder das Androhen dessen (\"Doxing\").",
|
||||||
|
"4": "Absichtliche Einschüchterung, Stalking oder Verfolgung.",
|
||||||
|
"5": "Bewerben von Produkten und Dienstleistungen mit kommerzieller Absicht.",
|
||||||
|
"6": "Strafbares Verhalten bzw. Verstoß gegen deutsches Recht.",
|
||||||
|
"7": "Befürwortung oder Ermutigung zu diesen Verhaltensweisen."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"consequences": {
|
||||||
|
"title": "Konsequenzen inakzeptablen Verhaltens",
|
||||||
|
"description": "Wenn ein Gemeinschaftsmitglied inakzeptables Verhalten an den Tag legt, können die verantwortlichen Betreiber, Moderatoren und Administratoren des Netzwerks angemessene Maßnahmen ergreifen, u.a.:",
|
||||||
|
"list": {
|
||||||
|
"0": "Aufforderung zum sofortigen Abstellen des inakzeptablen Verhaltens",
|
||||||
|
"1": "Sperren oder Löschen von Kommentaren",
|
||||||
|
"2": "Temporärer Ausschluss aus dem jeweiligen Beitrag",
|
||||||
|
"3": "Sperren bzw. Löschen von Inhalten",
|
||||||
|
"4": "Temporärer Entzug von Schreibrechten",
|
||||||
|
"5": "Vorübergehender Ausschluss aus dem Netzwerk",
|
||||||
|
"6": "Endgültiger Ausschluss aus dem Netzwerk",
|
||||||
|
"7": "Verstöße gegen deutsches Recht können zur Anzeige gebracht werden.",
|
||||||
|
"8": "Meldung von Vorkommnissen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get-help": "Wenn du einem inakzeptablen Verhalten ausgesetzt bist, es miterlebst oder andere Bedenken hast, benachrichtige bitte so schnell wie möglich einen Organisator der Gemeinschaft und verlinke oder verweise auf den entsprechenden Inhalt:"
|
||||||
|
},
|
||||||
|
"termsAndConditions": {
|
||||||
|
"risk": {
|
||||||
|
"title": "Unfallgefahr",
|
||||||
|
"description": "Das ist eine Testversion! Alle Daten, Dein Profil und die Server können jederzeit komplett vernichtet, verloren, verbrannt und vielleicht auch in der Nähe von Alpha Centauri synchronisiert werden. Die Benutzung läuft auf eigene Gefahr. Mit kommerziellen Nebenwirkungen ist jedoch nicht zu rechnen."
|
||||||
|
},
|
||||||
|
"data-privacy": {
|
||||||
|
"title": "Du und deine Daten",
|
||||||
|
"description": "Bitte beachte, dass wir die Inhalte der Alphaversion zu Werbezwecken, Webpräsentationen usw. verwenden, aber wir glauben, dass das auch in Deinem Interesse ist. Am besten keinen Nachnamen eingeben und bei noch mehr Datensparsamkeit ein Profilfoto ohne Identität verwenden. Mehr in unserer <a href=\"/data-privacy\">Datenschutzerklärung</a>"
|
||||||
|
},
|
||||||
|
"work-in-progress": {
|
||||||
|
"title": "Baustellen",
|
||||||
|
"description": "Das ist immer noch eine Testversion. Wenn etwas nicht funktioniert, blockiert, irritiert, falsch angezeigt, verbogen oder nicht anklickbar ist, bitten wir dies zu entschuldigen. Fehler, Käfer und Bugs bitte melden! <a href=\"mailto:support@human-connection.org\" target=\"_blank\">support@human-connection.org</a>"
|
||||||
|
},
|
||||||
|
"code-of-conduct": {
|
||||||
|
"title": "Verhaltenscodex",
|
||||||
|
"description": "<a href=\"/code-of-conduct\">Die Verhaltensregeln </a> dienen als Leitsätze für den persönlichen Auftritt und den Umgang untereinander. Wer als Nutzer im Human Connection Netzwerk aktiv ist, Beiträge verfasst, kommentiert oder mit anderen Nutzern, auch außerhalb des Netzwerkes, Kontakt aufnimmt, erkennt diese Verhaltensregeln als verbindlich an"
|
||||||
|
},
|
||||||
|
"moderation": {
|
||||||
|
"title": "Moderation",
|
||||||
|
"description": "Solange kein Community-Moderationssystem lauffähig ist, entscheidet ein Regenbogen-Einhorn darüber, ob Du körperlich und psychisch stabil genug bist, unsere Testversion zu bedienen. Das Einhorn kann Dich jederzeit von der Alpha entfernen. Also sei nett und lass Regenbogenfutter da!"
|
||||||
|
},
|
||||||
|
"fairness": {
|
||||||
|
"title": "Fairness",
|
||||||
|
"description": "Sollte Dir die Alphaversion unseres Netzwerks wider Erwarten, egal aus welchen Gründen, nicht gefallen, überweisen wir Dir Deine gespendeten Monatsbeiträge innerhalb der ersten 2 Monate gerne zurück. Einfach Mail an: <a href=\"mailto:info@human-connection.org\" target=\"_blank\" s> info@human-connection.org </a> Achtung: Viele Funktionen werden erst nach und nach eingebaut."
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"title": "Fragen",
|
||||||
|
"description": "Die Termine und Links zu den Zoom-Räumen findest Du hier: <a href=\"https://human-connection.org/events-und-news/\" target=\"_blank\" >https://human-connection.org/veranstaltungen/ </a>"
|
||||||
|
},
|
||||||
|
"human-connection": {
|
||||||
|
"title": "Von Menschen für Menschen:",
|
||||||
|
"description": "Bitte hilf uns weitere monatlichen Spender für Human Connection zu bekommen, damit das Netzwerk so schnell wie möglich offiziell an den Start gehen kann. <a href=\"https://human-connection.org/\" target=\"_blank\"> https://human-connection.org </a>"
|
||||||
|
},
|
||||||
|
"have-fun": "Jetzt aber viel Spaß mit der Alpha von Human Connection! Für den ersten Weltfrieden. ♥︎",
|
||||||
|
"closing": "Herzlichst <br><br> Euer Human Connection Team"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,8 @@
|
|||||||
"site": {
|
"site": {
|
||||||
"made": "Made with ❤",
|
"made": "Made with ❤",
|
||||||
"imprint": "Imprint",
|
"imprint": "Imprint",
|
||||||
"termsAc": "Terms and conditions",
|
"termsAndConditions": "Terms and conditions",
|
||||||
"privacy": "Data privacy",
|
"data-privacy": "Data privacy",
|
||||||
"changelog": "Changes & History",
|
"changelog": "Changes & History",
|
||||||
"contact": "Contact",
|
"contact": "Contact",
|
||||||
"tribunal": "Registry court",
|
"tribunal": "Registry court",
|
||||||
@ -21,7 +21,8 @@
|
|||||||
"taxident": "USt-ID. according to §27a of the German Sales Tax Law:",
|
"taxident": "USt-ID. according to §27a of the German Sales Tax Law:",
|
||||||
"responsible": "responsible for contents of this page (§ 55 Abs. 2 RStV)",
|
"responsible": "responsible for contents of this page (§ 55 Abs. 2 RStV)",
|
||||||
"bank": "bank account",
|
"bank": "bank account",
|
||||||
"germany": "Germany"
|
"germany": "Germany",
|
||||||
|
"code-of-conduct": "Code of Conduct"
|
||||||
},
|
},
|
||||||
"sorting": {
|
"sorting": {
|
||||||
"newest": "Newest",
|
"newest": "Newest",
|
||||||
@ -390,17 +391,20 @@
|
|||||||
"user": {
|
"user": {
|
||||||
"title": "Release User",
|
"title": "Release User",
|
||||||
"type": "User",
|
"type": "User",
|
||||||
"message": "Do you really want to release the user \"<b>{name}</b>\"?"
|
"message": "Do you really want to release the user \"<b>{name}</b>\"?",
|
||||||
|
"error": "You already reported the user!"
|
||||||
},
|
},
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"title": "Release Contribution",
|
"title": "Release Contribution",
|
||||||
"type": "Contribution",
|
"type": "Contribution",
|
||||||
"message": "Do you really want to release the contribution \"<b>{name}</b>\"?"
|
"message": "Do you really want to release the contribution \"<b>{name}</b>\"?",
|
||||||
|
"error": "You have already reported the contribution!!"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Release Comment",
|
"title": "Release Comment",
|
||||||
"type": "Comment",
|
"type": "Comment",
|
||||||
"message": "Do you really want to release the comment from \"<b>{name}</b>\"?"
|
"message": "Do you really want to release the comment from \"<b>{name}</b>\"?",
|
||||||
|
"error": "You have already reported the comment!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
@ -418,7 +422,118 @@
|
|||||||
"infoSelectedNoOfMaxCategories": "{chosen} of {max} categories selected"
|
"infoSelectedNoOfMaxCategories": "{chosen} of {max} categories selected"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terms": {
|
"changelog": {
|
||||||
"text": "<div><ol><li><strong>RISK OF ACCIDENT:</strong> This is a test version! All data, your profile and the server can be completely destroyed, wiped out, lost, burnt and eventually synchronised near Alpha Centauri at any time. Use on your own risk. Commercial effects are not likely though.</li><br><li><strong>YOU AND YOUR DATA:</strong> Please notice, that the content of the alpha version will be used for publicity and web presentations etc. but we are sure, this is to your interest. If you like use no surnames and if you want to disclose less data use a profile picture without identity. You can find more information in our <a href='/pages/privacy' target='_blank'>privacy policy</a>.</li><br><li><strong>SITE:</strong> This is still a test version. Please excuse if some applications are not working, blocking, irritating, displayed falsely or not able to be clicked on. Please report faults and bugs! <a href='https://human-connection.org/support' target='_blank'>https://human-connection.org/support</a></li><br><li><strong>CODE OF CONDUCT</strong>: The code of conduct serves as guiding principles for our personal appearance and interaction with one another. Anyone who is active as a user in the Human Connection Network, writes articles, comments or contacts other users, including those outside the network, acknowledges these rules of conduct as binding: <a href='https://alpha.human-connection.org/pages/code-of-conduct' target='_blank'>https://alpha.human-connection.org/pages/code-of-conduct</a></li><br><li><strong>MODERATION:</strong> As long as there is no community moderation-system in operation, a rainbow colored unicorn decides, if you are physically and mentally stable enough to operate our test version. The unicorn can delete you from the alpha version at any time. So be so kind and leave rainbow food!</li><br><li><strong>FAIRNESS:</strong> If, against all expectations, our alpha version is not to your liking, we return your monthly payment within the first two months. Please send a mail to: <a href='mailto:info@human-connection.org' target='_blank'>info@human-connection.org</a>. <strong>Attention: Pleace note that more features are build in on regular basis.</strong></li><br><li><strong>QUESTIONS?</strong> You can find the dates and links to our zoom-rooms here: <a href='https://human-connection.org/events-und-news/' target='_blank'>https://human-connection.org/events-und-news/</a></li><br><li><strong>FROM HUMAN BEING TO HUMAN BEING: </strong>Please help us to get new donators for Human Connection, so the network can take off as soon as possible. <a href='https://human-connection.org/' target='_blank'>https://human-connection.org</a></li></ol><br><p>Now have fun with the alpha version of Human Connection! For the first universal peace.<strong> ♥︎</strong></p><p><strong> </strong></p><br><p><strong>Thank you very much, </strong></p><p><strong>your Human Connection Team</strong></p></div>"
|
"24": "Dialog for password change has been added.",
|
||||||
|
"23": "An editor for writing posts has been added.",
|
||||||
|
"22": "A dialogue for blocking content which violates the terms of service had been added for the moderators.",
|
||||||
|
"21": "The 'Shout' button has been added to the article view.",
|
||||||
|
"20": "Automated deployment of the software has been fixed so that new features can always be tested immediately.",
|
||||||
|
"19": "All software repositories on Github have been merged into one to avoid independent version information and incompatible interfaces",
|
||||||
|
"18": "The automated import of data from the Alpha-version to the Nitro had been tested with test data",
|
||||||
|
"17": "The web interface of the Nitro had been tested for correct display on mobile devices.",
|
||||||
|
"16": "A Button for reporting abusive content has been added",
|
||||||
|
"15": "An moderation backend for reported content has been implemented",
|
||||||
|
"14": "A Bug with the user authentication has been fixed",
|
||||||
|
"13": "User can input country, region or city and it is her / his decision how accurate it should be.",
|
||||||
|
"12": "User settings field for setting the interface and preferred content language",
|
||||||
|
"11": "Integration of Nuxt-i18n toolkit for support of server-side rendered pages of webapps",
|
||||||
|
"10": "Integration of Lokalise.co pipeline for translations + Updated used toolkits and frameworks to newest versions",
|
||||||
|
"9": "[in progress] Add icons to categories and tagging (how many users are using this tag, not how often the tag is used generally)",
|
||||||
|
"8": "Updated to actual eslint version for source code quality",
|
||||||
|
"7": "[in progress] Coding a blacklist for Nitro to hide unwanted user's content",
|
||||||
|
"6": "Coding a feature, so users who haven't donated yet, get a chance later to do so",
|
||||||
|
"5": "Coding a database query to identify users, which had not completed the registration dialog",
|
||||||
|
"4": "Introduction of a versioning scheme to identify the running social network code version",
|
||||||
|
"3": "Login for the new Nitro version with a fancier interface.",
|
||||||
|
"2": "Moved project planning to Zenhub",
|
||||||
|
"1": "Decided to use Scrum for project management",
|
||||||
|
"0": "Started work on \"Nitro\". The database and the server interface are replaced:"
|
||||||
|
},
|
||||||
|
"code-of-conduct": {
|
||||||
|
"subheader": "for the social network of the Human Connection gGmbH",
|
||||||
|
"preamble": {
|
||||||
|
"title": "Preamble",
|
||||||
|
"description": "Human Connection is a non-profit social knowledge and action network of the next generation. By people - for people. Open Source, fair and transparent. For positive local and global change in all areas of life. We completely redesign the public exchange of knowledge, ideas and projects. The functions of Human Connection bring people together - offline and online - so that we can make the world a better place."
|
||||||
|
},
|
||||||
|
"purpose": {
|
||||||
|
"title": "Purpose",
|
||||||
|
"description": "With these code of conduct we regulate the essential principles for behavior in our social network. The United Nations Charter of Human Rights is our orientation and forms the heart of our understanding of values. The code of conduct serves as guiding principles for our personal appearance and interaction with one another. Anyone who is active as a user in the Human Connection Network, writes articles, comments or contacts other users, including those outside the network,acknowledges these rules of conduct as binding."
|
||||||
|
},
|
||||||
|
"expected-behaviour": {
|
||||||
|
"title": "Expected Behaviour",
|
||||||
|
"description": "The following behaviors are expected and requested of all community members:",
|
||||||
|
"list": {
|
||||||
|
"0": "Exercise consideration and respect in your speech and actions.",
|
||||||
|
"1": "Attempt collaboration before conflict.",
|
||||||
|
"2": "Refrain from demeaning, discriminatory, or harassing behavior and speech.",
|
||||||
|
"3": "Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unacceptable-behaviour": {
|
||||||
|
"title": "Unacceptable Behavior",
|
||||||
|
"description": "The following behaviors are unacceptable within our community:",
|
||||||
|
"list": {
|
||||||
|
"0": "Discriminatory posts, comments, utterances or insults, particularly those relating to gender, sexual orientation, race, religion, political or philosophical orientation or disability.",
|
||||||
|
"1": "Posting or linking of clearly pornographic material.",
|
||||||
|
"2": "Glorification or trivialization of cruel or inhuman acts of violence.",
|
||||||
|
"3": "The disclosure of others' personal information without their consent or threat there of (\"doxing\").",
|
||||||
|
"4": "Intentional intimidation, stalking or persecution.",
|
||||||
|
"5": "Advertising products and services with commercial intent.",
|
||||||
|
"6": "Criminal behavior or violation of German law.",
|
||||||
|
"7": "Endorse or encourage such conduct."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"consequences": {
|
||||||
|
"title": "Consequences of Unacceptable Behavior",
|
||||||
|
"description": "If a community member exhibits unacceptable behaviour, the responsible operators, moderators and administrators of the network may take appropriate measures, including but not limited to:",
|
||||||
|
"list": {
|
||||||
|
"0": "Request for immediate cessation of unacceptable conduct",
|
||||||
|
"1": "Locking or deleting comments",
|
||||||
|
"2": "Temporary exclusion from the respective post or contribution",
|
||||||
|
"3": "Blocking or deleting of content",
|
||||||
|
"4": "Temporary withdrawal of write permissions",
|
||||||
|
"5": "Temporary exclusion from the network",
|
||||||
|
"6": "Final exclusion from the network",
|
||||||
|
"7": "Violations of German law can be reported.",
|
||||||
|
"8": "Advocacy or encouragement to these behaviors."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get-help": "If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible and link or refer to the corresponding content:"
|
||||||
|
},
|
||||||
|
"termsAndConditions": {
|
||||||
|
"risk": {
|
||||||
|
"title": "Risk of accident",
|
||||||
|
"description": "This is a test version! All data, your profile and the server can be completely destroyed, wiped out, lost, burnt and eventually synchronised near Alpha Centauri at any time. Use on your own risk. Commercial effects are not likely though."
|
||||||
|
},
|
||||||
|
"data-privacy": {
|
||||||
|
"title": "You and your data",
|
||||||
|
"description": "Please note that the content of the alpha version will be used for public web presentations etc. but we are sure, this is in your interest. Avoid real names and use anonymous profile pictures without your face. You can find more information in our <a href=\"/data-privacy\">data privacy policy</a>"
|
||||||
|
},
|
||||||
|
"work-in-progress": {
|
||||||
|
"title": "Work in progress",
|
||||||
|
"description": "This is still a test version. Please excuse if some applications are not working, blocking, irritating, displayed falsely or not able to be clicked on. Please report faults and bugs! <a href=\"mailto:support@human-connection.org\" target=\"_blank\">mailto:support@human-connection.org</a>"
|
||||||
|
},
|
||||||
|
"code-of-conduct": {
|
||||||
|
"title": "Code of conduct",
|
||||||
|
"description": "The <a href=\"/code-of-conduct\">code of conduct</a> serves as guiding principles for our personal appearance and interaction with one another. Anyone who is active as a user in the Human Connection Network, writes articles, comments or contacts other users, including those outside the network, acknowledges these rules of conduct as binding."
|
||||||
|
},
|
||||||
|
"moderation": {
|
||||||
|
"title": "Moderation",
|
||||||
|
"description": "As long as there is no community moderation-system in operation, a rainbow colored unicorn decides, if you are physically and mentally stable enough to operate our test version. The unicorn can delete you from the alpha version at any time. So be so kind and leave rainbow food!"
|
||||||
|
},
|
||||||
|
"fairness": {
|
||||||
|
"title": "Fairness",
|
||||||
|
"description": "If, against all expectations, our alpha version is not to your liking, we return your monthly payment within the first two months. Please send a mail to: <a href=\"mailto:info@human-connection.org\" target=\"_blank\"> info@human-connection.org </a> Note that more features are added on a regular basis."
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"title": "Questions",
|
||||||
|
"description": "You can find the dates and links to our zoom-rooms here: <a href=\"https://human-connection.org/en/events/\" target=\"_blank\" >https://human-connection.org/en/events/ </a>"
|
||||||
|
},
|
||||||
|
"human-connection": {
|
||||||
|
"title": "By humans for humans",
|
||||||
|
"description": "Please help us to get new donators for Human Connection, so the network can take off as soon as possible. <a href=\"https://human-connection.org/\" target=\"_blank\"> https://human-connection.org </a>"
|
||||||
|
},
|
||||||
|
"have-fun": "Now have fun with the alpha version of Human Connection! For the first universal peace. ♥︎",
|
||||||
|
"closing": "Thank you very much <br> <br> your Human Connection Team"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"made": "Con ❤ realizado",
|
"made": "Con ❤ realizado",
|
||||||
"imprint": "Pie de imprenta",
|
"imprint": "Pie de imprenta",
|
||||||
"termsAc": "términos y condiciones",
|
"termsAc": "términos y condiciones",
|
||||||
"privacy": "protección de datos",
|
"data-privacy": "protección de datos",
|
||||||
"changelog": "Cambios e historia",
|
"changelog": "Cambios e historia",
|
||||||
"contact": "Contacto",
|
"contact": "Contacto",
|
||||||
"tribunal": "tribunal de registro",
|
"tribunal": "tribunal de registro",
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"made": "Avec ❤ fait",
|
"made": "Avec ❤ fait",
|
||||||
"imprint": "Mentions légales",
|
"imprint": "Mentions légales",
|
||||||
"termsAc": "modalités et conditions",
|
"termsAc": "modalités et conditions",
|
||||||
"privacy": "protection des données",
|
"data-privacy": "protection des données",
|
||||||
"changelog": "Changements et historique",
|
"changelog": "Changements et historique",
|
||||||
"contact": "Contacter",
|
"contact": "Contacter",
|
||||||
"tribunal": "tribunal de registre",
|
"tribunal": "tribunal de registre",
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"made": "Con ❤ fatto",
|
"made": "Con ❤ fatto",
|
||||||
"imprint": "Impressum",
|
"imprint": "Impressum",
|
||||||
"termsAc": "Condizioni d'uso",
|
"termsAc": "Condizioni d'uso",
|
||||||
"privacy": "protezione dei dati",
|
"data-privacy": "protezione dei dati",
|
||||||
"changelog": "Cambiamenti e storia",
|
"changelog": "Cambiamenti e storia",
|
||||||
"contact": "Contatto",
|
"contact": "Contatto",
|
||||||
"tribunal": "registro tribunale",
|
"tribunal": "registro tribunale",
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"made": "Met ❤ gemaakt",
|
"made": "Met ❤ gemaakt",
|
||||||
"imprint": "Afdruk",
|
"imprint": "Afdruk",
|
||||||
"termsAc": "Gebruiksvoorwaarden",
|
"termsAc": "Gebruiksvoorwaarden",
|
||||||
"privacy": "gegevensbescherming",
|
"data-privacy": "gegevensbescherming",
|
||||||
"changelog": "Veranderingen & Geschiedenis",
|
"changelog": "Veranderingen & Geschiedenis",
|
||||||
"contact": "contact",
|
"contact": "contact",
|
||||||
"tribunal": "registerrechtbank",
|
"tribunal": "registerrechtbank",
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"made": "Z ❤ zrobiony",
|
"made": "Z ❤ zrobiony",
|
||||||
"imprint": "Nadruk",
|
"imprint": "Nadruk",
|
||||||
"termsAc": "Warunki użytkowania",
|
"termsAc": "Warunki użytkowania",
|
||||||
"privacy": "ochrona danych",
|
"data-privacy": "ochrona danych",
|
||||||
"changelog": "Zmiany i historia",
|
"changelog": "Zmiany i historia",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"tribunal": "sąd rejestrowy",
|
"tribunal": "sąd rejestrowy",
|
||||||
@ -16,18 +16,17 @@
|
|||||||
"responsible": "Odpowiedzialny zgodnie z § 55 Abs. 2 RStV (Niemcy)",
|
"responsible": "Odpowiedzialny zgodnie z § 55 Abs. 2 RStV (Niemcy)",
|
||||||
"bank": "rachunek bankowy",
|
"bank": "rachunek bankowy",
|
||||||
"germany": "Niemcy"
|
"germany": "Niemcy"
|
||||||
|
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"copy": "Jeśli masz już konto Human Connection, zaloguj się tutaj.",
|
"copy": "Jeśli masz już konto Human Connection, zaloguj się tutaj.",
|
||||||
"login": "logowanie",
|
"login": "Logowanie",
|
||||||
"logout": "Wyloguj się",
|
"logout": "Wyloguj się",
|
||||||
"email": "Twój adres e-mail",
|
"email": "Twój adres e-mail",
|
||||||
"password": "Twoje hasło",
|
"password": "Twoje hasło",
|
||||||
"forgotPassword": "Zapomniałeś hasła?",
|
"forgotPassword": "Zapomniałeś hasła?",
|
||||||
"moreInfo": "Co to jest Human Connection?",
|
"moreInfo": "Co to jest Human Connection?",
|
||||||
"moreInfoURL": "https://human-connection.org/pl/",
|
"moreInfoURL": "https://human-connection.org/en/",
|
||||||
"moreInfoHint": "na stronę prezentacji",
|
"moreInfoHint": "idź po więcej szczegółów",
|
||||||
"hello": "Cześć"
|
"hello": "Cześć"
|
||||||
},
|
},
|
||||||
"password-reset": {
|
"password-reset": {
|
||||||
@ -51,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"placeholder": "Zostaw swoje inspirujące myśli...."
|
"placeholder": "Napisz coś inspirującego..."
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"name": "Mój profil",
|
"name": "Mój profil",
|
||||||
@ -61,27 +60,27 @@
|
|||||||
"following": "Obserwowani",
|
"following": "Obserwowani",
|
||||||
"shouted": "Krzyknij",
|
"shouted": "Krzyknij",
|
||||||
"commented": "Skomentuj",
|
"commented": "Skomentuj",
|
||||||
"userAnonym": "Anonimowy",
|
"userAnonym": "Anonymous",
|
||||||
"socialMedia": "Gdzie indziej mogę znaleźć",
|
"socialMedia": "Gdzie jeszcze mogę znaleźć",
|
||||||
"network": {
|
"network": {
|
||||||
"title": "Sieć",
|
"title": "Sieć",
|
||||||
"following": "jest następująca:",
|
"following": "obserwuje:",
|
||||||
"followingNobody": "nie podąża za nikim.",
|
"followingNobody": "nikogo nie obserwuje.",
|
||||||
"followedBy": "po którym następuje:",
|
"followedBy": "jest obserwowany:",
|
||||||
"followedByNobody": "nie jest śledzona przez nikogo.",
|
"followedByNobody": "nikt go nie obserwuje.",
|
||||||
"and": "i",
|
"and": "i",
|
||||||
"more": "więcej"
|
"more": "więcej"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"menu": {
|
"menu": {
|
||||||
"mentioned": "wspomniała o tobie na posterunku."
|
"mentioned": "wspomiał o Tobie we wpisie"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Wyszukiwanie",
|
"placeholder": "Szukaj",
|
||||||
"hint": "Czego szukasz?",
|
"hint": "Czego szukasz?",
|
||||||
"failed": "Nic nie znaleziono"
|
"failed": "Niczego nie znaleziono"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"name": "Ustawienia",
|
"name": "Ustawienia",
|
||||||
@ -97,20 +96,20 @@
|
|||||||
"name": "Bezpieczeństwo",
|
"name": "Bezpieczeństwo",
|
||||||
"change-password": {
|
"change-password": {
|
||||||
"button": "Zmień hasło",
|
"button": "Zmień hasło",
|
||||||
"success": "Hasło zostało pomyślnie zmienione!",
|
"success": "Hasło zostało zmienione!",
|
||||||
"label-old-password": "Twoje stare hasło",
|
"label-old-password": "Stare hasło",
|
||||||
"label-new-password": "Twoje nowe hasło",
|
"label-new-password": "Nowe hasło",
|
||||||
"label-new-password-confirm": "Potwierdź nowe hasło",
|
"label-new-password-confirm": "Potwierdź nowe hasło",
|
||||||
"message-old-password-required": "Wprowadź swoje stare hasło",
|
"message-old-password-required": "Podaj stare hasło",
|
||||||
"message-new-password-required": "Wprowadź nowe hasło",
|
"message-new-password-required": "Wprowadź nowe hasło",
|
||||||
"message-new-password-confirm-required": "Potwierdź nowe hasło.",
|
"message-new-password-confirm-required": "Potwierdź nowe hasło",
|
||||||
"message-new-password-missmatch": "Wpisz ponownie to samo hasło.",
|
"message-new-password-missmatch": "Wpisz to samo hasło ponownie",
|
||||||
"passwordSecurity": "Zabezpieczenie hasłem",
|
"passwordSecurity": "Siła hasła",
|
||||||
"passwordStrength0": "Bardzo niepewne hasło",
|
"passwordStrength0": "Hasło bardzo słabe",
|
||||||
"passwordStrength1": "Niepewne hasło",
|
"passwordStrength1": "Hasło słabe",
|
||||||
"passwordStrength2": "Hasło pośredniczące",
|
"passwordStrength2": "Hasło średnie",
|
||||||
"passwordStrength3": "Silne hasło",
|
"passwordStrength3": "Hasło silne",
|
||||||
"passwordStrength4": "Bardzo mocne hasło"
|
"passwordStrength4": "Hasło bardzo silne"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invites": {
|
"invites": {
|
||||||
@ -120,26 +119,26 @@
|
|||||||
"name": "Pobierz dane"
|
"name": "Pobierz dane"
|
||||||
},
|
},
|
||||||
"deleteUserAccount": {
|
"deleteUserAccount": {
|
||||||
"name": "Usuwanie danych",
|
"name": "Usuń dane",
|
||||||
"contributionsCount": "Usuń moje stanowiska.",
|
"contributionsCount": "Usuń {count} moich postów",
|
||||||
"commentsCount": "Usuń moje komentarze {liczba}.",
|
"commentsCount": "Usuń {count} moich komentarzy",
|
||||||
"accountDescription": "Bądź świadomy, że Twój post i komentarze są ważne dla naszej społeczności. Jeśli nadal chcesz je usunąć, musisz zaznaczyć je poniżej.",
|
"accountDescription": "Be aware that your Post and Comments are important to our community. If you still choose to delete them, you have to mark them below.",
|
||||||
"accountWarning": "<b>Nie możesz zarządzać</b> i <b>Nie możesz REKOVER</b> swoje konto, posty lub komentarze po usunięciu konta!",
|
"accountWarning": "Po usunięcie Twojego konta, nie możesz <b>ZARZĄDZAĆ</b> ani <b>ODZYSKAĆ</b> danych, wpisów oraz komentarzy!",
|
||||||
"success": "Konto zostało pomyślnie usunięte",
|
"success": "Konto zostało usunięte",
|
||||||
"pleaseConfirm": "<b class='is-danger'>Niszczycielskie działanie!</b> Typ <b>{potwierdź}</b> aby potwierdzić"
|
"pleaseConfirm": "<b class='is-danger'>Uwaga, niebezpieczeństwo!</b> Wpisz <b>{confirm}</b>, aby potwierdzić"
|
||||||
},
|
},
|
||||||
"organizations": {
|
"organizations": {
|
||||||
"name": "My Organizations"
|
"name": "My Organizations"
|
||||||
},
|
},
|
||||||
"languages": {
|
"languages": {
|
||||||
"name": "Languages"
|
"name": "Języki"
|
||||||
},
|
},
|
||||||
"social-media": {
|
"social-media": {
|
||||||
"name": "Social media",
|
"name": "Media społecznościowe",
|
||||||
"placeholder": "Add social media url",
|
"placeholder": "Dodaj link do mediów społecznościowych",
|
||||||
"submit": "Add link",
|
"submit": "Dodaj link",
|
||||||
"successAdd": "Added social media. Updated user profile!",
|
"successAdd": "Dodano społeczność. Profil zaktualizowany!",
|
||||||
"successDelete": "Deleted social media. Updated user profile!"
|
"successDelete": "Usunięto społeczność. Profil zaktualizowany!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
@ -188,15 +187,15 @@
|
|||||||
"name": "Więcej informacji"
|
"name": "Więcej informacji"
|
||||||
},
|
},
|
||||||
"takeAction": {
|
"takeAction": {
|
||||||
"name": "Podejmij działania"
|
"name": "Podejmij działanie"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"edit": "Edytuj Post",
|
"edit": "Edytuj wpis",
|
||||||
"delete": "Usuń wpis"
|
"delete": "Usuń wpis"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"submit": "Komentarz",
|
"submit": "Komentarz",
|
||||||
"submitted": "Przedłożony komentarz"
|
"submitted": "Komentarz dodany"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
@ -253,16 +252,16 @@
|
|||||||
"moderation": {
|
"moderation": {
|
||||||
"name": "Umiarkowanie",
|
"name": "Umiarkowanie",
|
||||||
"reports": {
|
"reports": {
|
||||||
"empty": "Gratulacje, nic do umiarkowanego.",
|
"empty": "Gratulacje, moderacja nie jest potrzebna",
|
||||||
"name": "Sprawozdania",
|
"name": "Raporty",
|
||||||
"submitter": "zgłaszane przez",
|
"submitter": "zgłoszone przez",
|
||||||
"disabledBy": "niepełnosprawni przez"
|
"disabledBy": "deaktywowane przez"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"disable": {
|
"disable": {
|
||||||
"submit": "Niepełnosprawność",
|
"submit": "Deaktywuj",
|
||||||
"cancel": "Odwołaj",
|
"cancel": "Anuluj",
|
||||||
"success": "Niepełnosprawni skutecznie",
|
"success": "Zdeaktywowano",
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Wyłączenie użytkownika",
|
"title": "Wyłączenie użytkownika",
|
||||||
"type": "Użytkownik",
|
"type": "Użytkownik",
|
||||||
@ -283,38 +282,37 @@
|
|||||||
"submit": "Usuń",
|
"submit": "Usuń",
|
||||||
"cancel": "Odwołaj",
|
"cancel": "Odwołaj",
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"title": "Usuń Post",
|
"title": "Ukryj wpis",
|
||||||
"type": "Wkład",
|
"type": "Wpis / Post",
|
||||||
"message": "Naprawdę chcesz usunąć post \"<b>{name}</b>\"?",
|
"message": "Czy na pewno chcesz ukryć wpis \" <b> {name} </b> \"?",
|
||||||
"success": "Wyślij pomyślnie usunięty!"
|
"success": "Wyślij pomyślnie usunięty!"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Usuń komentarz",
|
"title": "Usuń komentarz",
|
||||||
"type": "Komentarz",
|
"type": "Komentarz",
|
||||||
"message": "Czy naprawdę chcesz usunąć komentarz \"<b>{name}</b>\"?",
|
"message": "Czy na pewno chcesz ukryć komentarz użytkownika \" <b> {name} </b> \"?"
|
||||||
"success": "Komentarz został pomyślnie usunięty!"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"submit": "Sprawozdanie",
|
"submit": "Wyślij raport",
|
||||||
"cancel": "Odwołaj",
|
"cancel": "Anuluj",
|
||||||
"success": "Dzięki za zgłoszenie!",
|
"success": "Dziękujemy za Twoje zgłoszenie!",
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Raport Użytkownik",
|
"title": "Raport Użytkownik",
|
||||||
"type": "Użytkownik",
|
"type": "Użytkownik",
|
||||||
"message": "Naprawdę chcesz zgłosić użytkownika \"<b>{name}</b>\"?",
|
"message": "Czy na pewno chcesz zgłosić użytkownika \" <b> {name} </b> \"?",
|
||||||
"error": "Zgłosiłeś już użytkownika!"
|
"error": "Zgłosiłeś już użytkownika!"
|
||||||
},
|
},
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"title": "Wkład w raport",
|
"title": "Zgłoś wpis",
|
||||||
"type": "Wkład",
|
"type": "Wpis / Post",
|
||||||
"message": "Naprawdę chcesz zgłosić wkład, jaki wniosłaś do programu \"<b>{name}</b>\"?",
|
"message": "Czy na pewno chcesz zgłosić ten wpis użytkownika \" <b> {name} </b> \"?",
|
||||||
"error": "Zgłosiłeś już ten wkład!"
|
"error": "Zgłosiłeś już ten wkład!"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Sprawozdanie Komentarz",
|
"title": "Sprawozdanie Komentarz",
|
||||||
"type": "Komentarz",
|
"type": "Komentarz",
|
||||||
"message": "Naprawdę chcesz zgłosić komentarz od \"<b>{name}</b>\"?",
|
"message": "Czy na pewno chcesz zgłosić komentarz użytkownika\" <b> {name} </b> \"?",
|
||||||
"error": "Zgłosiłeś już komentarz!"
|
"error": "Zgłosiłeś już komentarz!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -323,38 +321,38 @@
|
|||||||
"following": "w skutek"
|
"following": "w skutek"
|
||||||
},
|
},
|
||||||
"shoutButton": {
|
"shoutButton": {
|
||||||
"shouted": "wykrzyczany"
|
"shouted": "krzyczeć"
|
||||||
},
|
},
|
||||||
"release": {
|
"release": {
|
||||||
"submit": "Zwolnienie",
|
"submit": "Zgłoś",
|
||||||
"cancel": "Odwołaj",
|
"cancel": "Anuluj",
|
||||||
"success": "Wydany z powodzeniem!",
|
"success": "Zgłoszono pomyślnie!",
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Zwolnienie użytkownika",
|
"title": "Zgłoś użytkownika",
|
||||||
"type": "Użytkownik",
|
"type": "Użytkownik",
|
||||||
"message": "Naprawdę chcesz uwolnić użytkownika \"<b>{name}</b>\"?"
|
"message": "Czy na pewno chcesz zgłosić użytkownika \"<b> {name} </b>\"?"
|
||||||
},
|
},
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"title": "Zwolnienie Wkład",
|
"title": "Zgłoś wpis",
|
||||||
"type": "Wkład",
|
"type": "Wpis",
|
||||||
"message": "Naprawdę chcesz uwolnić swój wkład \"<b>{name}</b>\"?"
|
"message": "Czy na pewno chcesz zgłosić wpis użytkownika \"<b> {name} </b>\"?"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Zwolnienie komentarz",
|
"title": "Zgłoś komentarz",
|
||||||
"type": "komentarz",
|
"type": "Komentarz",
|
||||||
"message": "Czy naprawdę chcesz opublikować komentarz od \"<b>{name}</b>\"?"
|
"message": "Czy na pewno chcesz zgłosić komentarz użytkownika \"<b> {name} </b>\"?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"avatar": {
|
"avatar": {
|
||||||
"submitted": "Przesłanie udane"
|
"submitted": "Przesłano pomyślnie"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"newPost": "Utwórz nowy post",
|
"newPost": "Utwórz nowy wpis",
|
||||||
"filterFollow": "Filtrowanie wkładu użytkowników, za którymi podążam",
|
"filterFollow": "Pokaż wpisy użytkowników, których śledzę",
|
||||||
"filterALL": "Wyświetl wszystkie wkłady",
|
"filterALL": "Pokaż wszystkie wpisy",
|
||||||
"success": "Zachowany!",
|
"success": "Zapisano!",
|
||||||
"languageSelectLabel": "Język",
|
"languageSelectLabel": "Język",
|
||||||
"categories": {
|
"categories": {
|
||||||
"infoSelectedNoOfMaxCategories": "{chosen} z {max} wybrane kategorie"
|
"infoSelectedNoOfMaxCategories": "{chosen} z {max} wybrane kategorie"
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"made": "Com ❤ feito",
|
"made": "Com ❤ feito",
|
||||||
"imprint": "Impressão",
|
"imprint": "Impressão",
|
||||||
"termsAc": "termos e condições",
|
"termsAc": "termos e condições",
|
||||||
"privacy": "protecção de dados",
|
"data-privacy": "protecção de dados",
|
||||||
"changelog": "Mudanças e Histórico",
|
"changelog": "Mudanças e Histórico",
|
||||||
"contact": "Contato",
|
"contact": "Contato",
|
||||||
"tribunal": "tribunal",
|
"tribunal": "tribunal",
|
||||||
|
|||||||
@ -3,12 +3,12 @@ const envWhitelist = ['NODE_ENV', 'MAINTENANCE', 'MAPBOX_TOKEN']
|
|||||||
const dev = process.env.NODE_ENV !== 'production'
|
const dev = process.env.NODE_ENV !== 'production'
|
||||||
|
|
||||||
const styleguidePath = '../Nitro-Styleguide'
|
const styleguidePath = '../Nitro-Styleguide'
|
||||||
const styleguideStyles = process.env.STYLEGUIDE_DEV ?
|
const styleguideStyles = process.env.STYLEGUIDE_DEV
|
||||||
[
|
? [
|
||||||
`${styleguidePath}/src/system/styles/main.scss`,
|
`${styleguidePath}/src/system/styles/main.scss`,
|
||||||
`${styleguidePath}/src/system/styles/shared.scss`,
|
`${styleguidePath}/src/system/styles/shared.scss`,
|
||||||
] :
|
]
|
||||||
'@human-connection/styleguide/dist/shared.scss'
|
: '@human-connection/styleguide/dist/shared.scss'
|
||||||
|
|
||||||
const buildDir = process.env.NUXT_BUILD || '.nuxt'
|
const buildDir = process.env.NUXT_BUILD || '.nuxt'
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ module.exports = {
|
|||||||
|
|
||||||
modern: !dev ? 'server' : false,
|
modern: !dev ? 'server' : false,
|
||||||
|
|
||||||
transition: {
|
pageTransition: {
|
||||||
name: 'slide-up',
|
name: 'slide-up',
|
||||||
mode: 'out-in',
|
mode: 'out-in',
|
||||||
},
|
},
|
||||||
@ -39,6 +39,11 @@ module.exports = {
|
|||||||
'registration-verify-code',
|
'registration-verify-code',
|
||||||
'registration-create-user-account',
|
'registration-create-user-account',
|
||||||
'pages-slug',
|
'pages-slug',
|
||||||
|
'imprint',
|
||||||
|
'terms-and-conditions',
|
||||||
|
'code-of-conduct',
|
||||||
|
'data-privacy',
|
||||||
|
'changelog',
|
||||||
],
|
],
|
||||||
// pages to keep alive
|
// pages to keep alive
|
||||||
keepAlivePages: ['index'],
|
keepAlivePages: ['index'],
|
||||||
@ -51,7 +56,8 @@ module.exports = {
|
|||||||
head: {
|
head: {
|
||||||
title: 'Human Connection',
|
title: 'Human Connection',
|
||||||
titleTemplate: '%s - Human Connection',
|
titleTemplate: '%s - Human Connection',
|
||||||
meta: [{
|
meta: [
|
||||||
|
{
|
||||||
charset: 'utf-8',
|
charset: 'utf-8',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -64,11 +70,13 @@ module.exports = {
|
|||||||
content: pkg.description,
|
content: pkg.description,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
link: [{
|
link: [
|
||||||
rel: 'icon',
|
{
|
||||||
type: 'image/x-icon',
|
rel: 'icon',
|
||||||
href: '/favicon.ico',
|
type: 'image/x-icon',
|
||||||
}, ],
|
href: '/favicon.ico',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -95,37 +103,19 @@ module.exports = {
|
|||||||
/*
|
/*
|
||||||
** Plugins to load before mounting the App
|
** Plugins to load before mounting the App
|
||||||
*/
|
*/
|
||||||
plugins: [{
|
plugins: [
|
||||||
|
{
|
||||||
src: `~/plugins/styleguide${process.env.STYLEGUIDE_DEV ? '-dev' : ''}.js`,
|
src: `~/plugins/styleguide${process.env.STYLEGUIDE_DEV ? '-dev' : ''}.js`,
|
||||||
ssr: true,
|
ssr: true,
|
||||||
},
|
},
|
||||||
{
|
{ src: '~/plugins/i18n.js', ssr: true },
|
||||||
src: '~/plugins/i18n.js',
|
{ src: '~/plugins/axios.js', ssr: false },
|
||||||
ssr: true,
|
{ src: '~/plugins/keep-alive.js', ssr: false },
|
||||||
},
|
{ src: '~/plugins/vue-directives.js', ssr: false },
|
||||||
{
|
{ src: '~/plugins/v-tooltip.js', ssr: false },
|
||||||
src: '~/plugins/axios.js',
|
{ src: '~/plugins/izi-toast.js', ssr: false },
|
||||||
ssr: false,
|
{ src: '~/plugins/vue-filters.js' },
|
||||||
},
|
{ src: '~/plugins/vue-sweetalert-icons.js' },
|
||||||
{
|
|
||||||
src: '~/plugins/keep-alive.js',
|
|
||||||
ssr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: '~/plugins/vue-directives.js',
|
|
||||||
ssr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: '~/plugins/v-tooltip.js',
|
|
||||||
ssr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: '~/plugins/izi-toast.js',
|
|
||||||
ssr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: '~/plugins/vue-filters.js',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
router: {
|
router: {
|
||||||
@ -303,7 +293,9 @@ module.exports = {
|
|||||||
// Give apollo module options
|
// Give apollo module options
|
||||||
apollo: {
|
apollo: {
|
||||||
tokenName: 'human-connection-token', // optional, default: apollo-token
|
tokenName: 'human-connection-token', // optional, default: apollo-token
|
||||||
tokenExpires: 3, // optional, default: 7 (days)
|
cookieAttributes: {
|
||||||
|
expires: 3, // optional, default: 7 (days)
|
||||||
|
},
|
||||||
// includeNodeModules: true, // optional, default: false (this includes graphql-tag for node_modules folder)
|
// includeNodeModules: true, // optional, default: false (this includes graphql-tag for node_modules folder)
|
||||||
|
|
||||||
// Watch loading state for all queries
|
// Watch loading state for all queries
|
||||||
@ -350,7 +342,8 @@ module.exports = {
|
|||||||
loader: 'vue-svg-loader',
|
loader: 'vue-svg-loader',
|
||||||
options: {
|
options: {
|
||||||
svgo: {
|
svgo: {
|
||||||
plugins: [{
|
plugins: [
|
||||||
|
{
|
||||||
removeViewBox: false,
|
removeViewBox: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
|
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
|
||||||
"dev:styleguide": "cross-env STYLEGUIDE_DEV=true yarn dev",
|
"dev:styleguide": "cross-env STYLEGUIDE_DEV=true yarn dev",
|
||||||
|
"storybook": "start-storybook -p 3002 -c storybook/",
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
"start": "cross-env node server/index.js",
|
"start": "cross-env node server/index.js",
|
||||||
"generate": "nuxt generate",
|
"generate": "nuxt generate",
|
||||||
@ -52,19 +53,20 @@
|
|||||||
"@human-connection/styleguide": "0.5.17",
|
"@human-connection/styleguide": "0.5.17",
|
||||||
"@nuxtjs/apollo": "^4.0.0-rc10",
|
"@nuxtjs/apollo": "^4.0.0-rc10",
|
||||||
"@nuxtjs/axios": "~5.5.4",
|
"@nuxtjs/axios": "~5.5.4",
|
||||||
"@nuxtjs/dotenv": "~1.3.0",
|
"@nuxtjs/dotenv": "~1.4.0",
|
||||||
"@nuxtjs/style-resources": "~0.1.2",
|
"@nuxtjs/style-resources": "~0.1.2",
|
||||||
"accounting": "~0.4.1",
|
"accounting": "~0.4.1",
|
||||||
"apollo-cache-inmemory": "~1.6.2",
|
"apollo-cache-inmemory": "~1.6.2",
|
||||||
"apollo-client": "~2.6.3",
|
"apollo-client": "~2.6.3",
|
||||||
"cookie-universal-nuxt": "~2.0.17",
|
"cookie-universal-nuxt": "~2.0.17",
|
||||||
"cross-env": "~5.2.0",
|
"cross-env": "~5.2.0",
|
||||||
"date-fns": "2.0.0-beta.3",
|
"date-fns": "2.0.0-beta.4",
|
||||||
"express": "~4.17.1",
|
"express": "~4.17.1",
|
||||||
"graphql": "~14.4.2",
|
"graphql": "~14.4.2",
|
||||||
"isemail": "^3.2.0",
|
"isemail": "^3.2.0",
|
||||||
"jsonwebtoken": "~8.5.1",
|
"jsonwebtoken": "~8.5.1",
|
||||||
"linkify-it": "~2.2.0",
|
"linkify-it": "~2.2.0",
|
||||||
|
"node-fetch": "^2.6.0",
|
||||||
"nuxt": "~2.8.1",
|
"nuxt": "~2.8.1",
|
||||||
"nuxt-dropzone": "^1.0.2",
|
"nuxt-dropzone": "^1.0.2",
|
||||||
"nuxt-env": "~0.1.0",
|
"nuxt-env": "~0.1.0",
|
||||||
@ -75,14 +77,17 @@
|
|||||||
"v-tooltip": "~2.0.2",
|
"v-tooltip": "~2.0.2",
|
||||||
"vue-count-to": "~1.0.13",
|
"vue-count-to": "~1.0.13",
|
||||||
"vue-izitoast": "1.1.2",
|
"vue-izitoast": "1.1.2",
|
||||||
"vue-sweetalert-icons": "~3.2.0",
|
"vuex-i18n": "~1.13.1",
|
||||||
"vuex-i18n": "~1.13.0",
|
"vue-sweetalert-icons": "~4.0.0",
|
||||||
"zxcvbn": "^4.4.2"
|
"zxcvbn": "^4.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "~7.5.5",
|
"@babel/core": "~7.5.5",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||||
"@babel/preset-env": "~7.5.5",
|
"@babel/preset-env": "~7.5.5",
|
||||||
|
"@storybook/addon-a11y": "^5.1.9",
|
||||||
|
"@storybook/addon-actions": "^5.1.9",
|
||||||
|
"@storybook/vue": "~5.1.9",
|
||||||
"@vue/cli-shared-utils": "~3.10.0",
|
"@vue/cli-shared-utils": "~3.10.0",
|
||||||
"@vue/eslint-config-prettier": "~5.0.0",
|
"@vue/eslint-config-prettier": "~5.0.0",
|
||||||
"@vue/server-test-utils": "~1.0.0-beta.29",
|
"@vue/server-test-utils": "~1.0.0-beta.29",
|
||||||
@ -90,6 +95,10 @@
|
|||||||
"babel-core": "~7.0.0-bridge.0",
|
"babel-core": "~7.0.0-bridge.0",
|
||||||
"babel-eslint": "~10.0.2",
|
"babel-eslint": "~10.0.2",
|
||||||
"babel-jest": "~24.8.0",
|
"babel-jest": "~24.8.0",
|
||||||
|
"babel-loader": "~8.0.6",
|
||||||
|
"babel-preset-vue": "~2.0.2",
|
||||||
|
"css-loader": "~2.1.1",
|
||||||
|
"core-js": "~2.6.9",
|
||||||
"eslint": "~5.16.0",
|
"eslint": "~5.16.0",
|
||||||
"eslint-config-prettier": "~6.0.0",
|
"eslint-config-prettier": "~6.0.0",
|
||||||
"eslint-config-standard": "~12.0.0",
|
"eslint-config-standard": "~12.0.0",
|
||||||
@ -109,8 +118,12 @@
|
|||||||
"nodemon": "~1.19.1",
|
"nodemon": "~1.19.1",
|
||||||
"prettier": "~1.18.2",
|
"prettier": "~1.18.2",
|
||||||
"sass-loader": "~7.1.0",
|
"sass-loader": "~7.1.0",
|
||||||
|
"style-loader": "~0.23.1",
|
||||||
|
"style-resources-loader": "~1.2.1",
|
||||||
"tippy.js": "^4.3.5",
|
"tippy.js": "^4.3.5",
|
||||||
"vue-jest": "~3.0.4",
|
"vue-jest": "~3.0.4",
|
||||||
"vue-svg-loader": "~0.12.0"
|
"vue-loader": "~15.7.0",
|
||||||
|
"vue-svg-loader": "~0.12.0",
|
||||||
|
"vue-template-compiler": "^2.6.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,16 +5,78 @@
|
|||||||
</ds-space>
|
</ds-space>
|
||||||
|
|
||||||
<ds-container>
|
<ds-container>
|
||||||
<ds-space margin-top="large">
|
<strong>
|
||||||
<ds-text>{{ $t('site.changelog') }}</ds-text>
|
{{ Date.parse('2019-03') | date('MMMM yyyy') }}
|
||||||
<ds-text>...</ds-text>
|
</strong>
|
||||||
</ds-space>
|
<ul>
|
||||||
|
<li>{{ $t('changelog.24') }}</li>
|
||||||
|
<li>{{ $t('changelog.23') }}</li>
|
||||||
|
<li>{{ $t('changelog.22') }}</li>
|
||||||
|
<li>{{ $t('changelog.21') }}</li>
|
||||||
|
<li>{{ $t('changelog.20') }}</li>
|
||||||
|
</ul>
|
||||||
|
<strong>
|
||||||
|
{{ Date.parse('2019-02') | date('MMMM yyyy') }}
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>{{ $t('changelog.19') }}</li>
|
||||||
|
<li>{{ $t('changelog.18') }}</li>
|
||||||
|
<li>{{ $t('changelog.17') }}</li>
|
||||||
|
</ul>
|
||||||
|
<strong>
|
||||||
|
{{ Date.parse('2019-01') | date('MMMM yyyy') }}
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>{{ $t('changelog.16') }}</li>
|
||||||
|
<li>{{ $t('changelog.15') }}</li>
|
||||||
|
<li>{{ $t('changelog.14') }}</li>
|
||||||
|
<li>{{ $t('changelog.13') }}</li>
|
||||||
|
<li>{{ $t('changelog.12') }}</li>
|
||||||
|
<li>{{ $t('changelog.11') }}</li>
|
||||||
|
<li>{{ $t('changelog.10') }}</li>
|
||||||
|
</ul>
|
||||||
|
<strong>
|
||||||
|
{{ Date.parse('2018-12') | date('MMMM yyyy') }}
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>{{ $t('changelog.9') }}</li>
|
||||||
|
<li>{{ $t('changelog.8') }}</li>
|
||||||
|
<li>{{ $t('changelog.7') }}</li>
|
||||||
|
</ul>
|
||||||
|
<strong>
|
||||||
|
{{ Date.parse('2018-11') | date('MMMM yyyy') }}
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>{{ $t('changelog.6') }}</li>
|
||||||
|
<li>{{ $t('changelog.5') }}</li>
|
||||||
|
<li>{{ $t('changelog.4') }}</li>
|
||||||
|
<li>{{ $t('changelog.3') }}</li>
|
||||||
|
<li>{{ $t('changelog.2') }}</li>
|
||||||
|
<li>{{ $t('changelog.1') }}</li>
|
||||||
|
</ul>
|
||||||
|
<strong>
|
||||||
|
{{ Date.parse('2018-10') | date('MMMM yyyy') }}
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{{ $t('changelog.0') }}
|
||||||
|
<br />
|
||||||
|
<a
|
||||||
|
class="hc-editor-link-blot"
|
||||||
|
href="https://www.youtube.com/watch?v=8j2H0vnQEoQ"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
https://www.youtube.com/watch?v=8j2H0vnQEoQ
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
layout: 'default',
|
||||||
head() {
|
head() {
|
||||||
return {
|
return {
|
||||||
title: this.$t('site.changelog'),
|
title: this.$t('site.changelog'),
|
||||||
|
|||||||
64
webapp/pages/code-of-conduct.vue
Normal file
64
webapp/pages/code-of-conduct.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ds-space>
|
||||||
|
<ds-heading tag="h2">{{ $t('site.code-of-conduct') }}</ds-heading>
|
||||||
|
<p>{{ $t('code-of-conduct.subheader') }}</p>
|
||||||
|
</ds-space>
|
||||||
|
|
||||||
|
<ds-container>
|
||||||
|
<div v-for="section in sections" :key="section">
|
||||||
|
<strong>{{ $t(`code-of-conduct.${section}.title`) }}</strong>
|
||||||
|
<p>{{ $t(`code-of-conduct.${section}.description`) }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div v-for="section in listSections" :key="section.key">
|
||||||
|
<strong>{{ $t(`code-of-conduct.${section.key}.title`) }}</strong>
|
||||||
|
<p>{{ $t(`code-of-conduct.${section.key}.description`) }}</p>
|
||||||
|
<ul>
|
||||||
|
<li v-for="i in section.items" :key="i">
|
||||||
|
{{ $t(`code-of-conduct.${section.key}.list.${i}`) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ $t('code-of-conduct.get-help') }}
|
||||||
|
<a class="hc-editor-link-blot" href="moderation@human-connection.org" target="_blank">
|
||||||
|
moderation@human-connection.org
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
</ds-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
head() {
|
||||||
|
return {
|
||||||
|
title: this.$t('site.code-of-conduct'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sections: ['preamble', 'purpose'],
|
||||||
|
listSections: [
|
||||||
|
{
|
||||||
|
key: 'expected-behaviour',
|
||||||
|
items: [...Array(4).keys()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unacceptable-behaviour',
|
||||||
|
items: [...Array(8).keys()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'consequences',
|
||||||
|
items: [...Array(9).keys()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
395
webapp/pages/data-privacy.vue
Normal file
395
webapp/pages/data-privacy.vue
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ds-space>
|
||||||
|
<ds-heading tag="h2">{{ $t('site.data-privacy') }}</ds-heading>
|
||||||
|
</ds-space>
|
||||||
|
<ds-container>
|
||||||
|
<ds-space margin-top="large">
|
||||||
|
<p>
|
||||||
|
für
|
||||||
|
<a href="https://alpha.human-connection.org" target="_blank">
|
||||||
|
https://alpha.human-connection.org
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Stand vom
|
||||||
|
<strong>17. Juni 2019</strong>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Human Connection gGmbH bietet über die Internetseite
|
||||||
|
<a href="https://alpha.human-connection.org" target="_blank">
|
||||||
|
https://alpha.human-connection.org
|
||||||
|
</a>
|
||||||
|
den Nutzern und Interessierten umfangreiche Informationen. Dabei liegt uns der
|
||||||
|
vertrauensvolle und sichere Umgang mit Deinen personenbezogenen Daten sehr am Herzen.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Auf Grund von rechtlichen und technischen Veränderungen, passen wir die
|
||||||
|
Datenschutzerklärung bei Bedarf an. Es ist jeweils die aktuellste Fassung unserer hier
|
||||||
|
veröffentlichten Datenschutzerklärung gültig.
|
||||||
|
</p>
|
||||||
|
<h1>Verantwortlicher</h1>
|
||||||
|
<p>
|
||||||
|
Verantwortlicher im Sinne der Datenschutz-Grundverordnung, sonstiger in den
|
||||||
|
Mitgliedstaaten der Europäischen Union geltenden Datenschutzgesetze und anderer
|
||||||
|
Bestimmungen mit datenschutzrechtlichem Charakter ist die:
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p><strong>Human Connection gGmbH</strong></p>
|
||||||
|
<p>Bahnhofstr. 11</p>
|
||||||
|
<p>73235 Weilheim / Teck</p>
|
||||||
|
<p>
|
||||||
|
<strong>Geschäftsführer:</strong>
|
||||||
|
Dennis Hack
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Telefon:</strong>
|
||||||
|
+49 151 43 80 42 22
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>E-Mail:</strong>
|
||||||
|
<a href="mailto:info@human-connection.org">info@human-connection.org</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Web:</strong>
|
||||||
|
<a href="https://human-connection.org" target="_blank">https://human-connection.org</a>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<h1>Datenschutzbeauftragter</h1>
|
||||||
|
<p><strong>Unser Datenschutzbeauftragte ist so erreichbar</strong></p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<strong>E-Mail:</strong>
|
||||||
|
<a href="mailto:datenschutz@human-connection.org">datenschutz@human-connection.org</a>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<h1>Zwecke der Datenverarbeitung</h1>
|
||||||
|
<p>
|
||||||
|
Die bei der Registrierung oder später von Dir angegebenen personenbezogenen Daten
|
||||||
|
verarbeiten wir nur zu den weiter unten genannten Zwecken. Wir übermitteln sie nicht an
|
||||||
|
Dritte zu weiteren Zwecken, außer:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>wir haben Deine ausdrückliche Einwilligung dazu,</li>
|
||||||
|
<li>die Verarbeitung ist zur Abwicklung eines Vertrages mit Dir erforderlich,</li>
|
||||||
|
<li>
|
||||||
|
die Verarbeitung ist zur Erfüllung einer rechtlichen Verpflichtung erforderlich oder
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
die Verarbeitung zur Wahrung berechtigter Interessen erforderlich ist und kein Grund zur
|
||||||
|
Annahme besteht, dass Du ein überwiegendes schutzwürdiges Interesse an der
|
||||||
|
Nichtweitergabe dieser Daten hast.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1>Deine Registrierung</h1>
|
||||||
|
<p>
|
||||||
|
Im Sinne der Datenminimierung registrierst Du Dich bei unserer Webanwendung einzig mit
|
||||||
|
Deiner E-Mail-Adresse. Weitere personenbezogene Daten sind für die Registrierung nicht
|
||||||
|
nötig. Die Registrierung ist notwendig, um unser Netzwerk nutzen zu können.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Über diese E-Mail-Adresse bist Du uns bekannt und ebenso dient diese als Deine Identität.
|
||||||
|
D.h., alle Rechte, die Du ausübst, hängen mit dieser Identität zusammen und über sie
|
||||||
|
erkennen wir, dass Du wirklich Du bist und nicht ein anderer.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
In der Kommunikation mit uns spielt die von Dir verwendete E-Mail-Adresse also eine
|
||||||
|
zentrale Rolle. Daher werden wir alle von Dir ausgeübten Rechte und ggf. Wünsche, die Du
|
||||||
|
an uns richtest, immer über Deine E-Mail-Adresse verifizieren. Niemals werden wir auf
|
||||||
|
Basis eines Anrufes oder einer sonstigen Information an Deinem Account etwas ändern, ihn
|
||||||
|
z.B. Löschen oder Stillegen, ohne diese Verifizierung – außer, wir sind durch ein Gesetz
|
||||||
|
dazu gezwungen.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Gesichert ist Deine Identität in unserem Netzwerk über ein Passwort, was von Dir selbst
|
||||||
|
vergeben werden muss und jederzeit geändert werden kann. Weitere Daten, wie Dein
|
||||||
|
Pseudonym, ein Avatar-Bildchen oder weitere Angaben, die ggf. auch personenbezogene Daten
|
||||||
|
sein können, vergibst Du selbst. Sie sind für die Registrierung selbst nicht nötig.
|
||||||
|
</p>
|
||||||
|
<h1>Allgemeine Nutzungsinformationen</h1>
|
||||||
|
<p>
|
||||||
|
Beim Abruf unserer Website werden von Deinem Browser Daten übertragen, die für den Abruf
|
||||||
|
und die Übermittlung technisch notwendig sind, zum Beispiel Deine IP-Adresse. Die
|
||||||
|
IP-Adresse kann zum Beispiel dazu dienen, Dich zu identifizieren und zählt daher zu den
|
||||||
|
personenbezogenen Daten.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Zusätzlich übermittelt Dein Browser mit jeder Anfrage an unseren Webserver weitere
|
||||||
|
Informationen ungefragt, zum Beispiel Informationen über Dein Betriebssystem oder Deinen
|
||||||
|
Webbrowser, die für eine Abfrage unserer Webseiten überflüssig sind und auch nicht
|
||||||
|
ausgewertet werden. Dies sind keine personenbezogenen Daten und lassen keinen Rückschluss
|
||||||
|
auf Deine Person zu.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Letztere Daten werden wir u.U. statistisch auswerten, um für die Nutzer unserer Plattform
|
||||||
|
Statistiken bereit zu stellen oder um unsere Plattform weiter zu optimieren,
|
||||||
|
beispielsweise um sie für besonders oft genutzte Browser oder Betriebssysteme optimal
|
||||||
|
anzupassen.
|
||||||
|
</p>
|
||||||
|
<h1>Löschung bzw. Sperrung</h1>
|
||||||
|
<p>
|
||||||
|
Wir folgen dem Grundsatz der Datenvermeidung und Datensparsamkeit. Daher speichern wir
|
||||||
|
Deine personenbezogenen Daten nur so lange, wie dies zur Erreichung der hier genannten
|
||||||
|
Zwecke erforderlich ist oder wie es die ggf. gesetzlich vorgesehenen Speicherfristen
|
||||||
|
vorsehen. Ist die Frist abgelaufen oder der Zweck nicht mehr gegeben, sperren oder löschen
|
||||||
|
wir diese Daten entsprechend den gesetzlichen Vorschriften.
|
||||||
|
</p>
|
||||||
|
<h1>Log-Files</h1>
|
||||||
|
<p>
|
||||||
|
Unsere Webserver schreiben Protokolle, um ggf. vorkommende Anwendungsfehler erkennen zu
|
||||||
|
können. Diese Protokolle enthalten keine IP-Adressen und werden von uns spätestens nach 7
|
||||||
|
Tagen gelöscht.
|
||||||
|
</p>
|
||||||
|
<h1>Cookies</h1>
|
||||||
|
<p>
|
||||||
|
Wie die meisten anderen Webseiten verwenden auch wir so genannte „Cookies“. Cookies sind
|
||||||
|
kleine Textdateien, die von einem Webserver in Deinem Browser gespeichert werden, um dort
|
||||||
|
bestimmte Informationen zu hinterlegen. Zum Beispiel, dass Du angemeldet bist, dass Du die
|
||||||
|
Website in einer bestimmten Sprache sehen möchtest oder um auf der Website zu navigieren.
|
||||||
|
Diese Daten sind nur in Deinem Browser gespeichert und werden von uns nicht weiter
|
||||||
|
gegeben. Für die Funktionalität unserer Website sind diese Cookies erforderlich. Sie
|
||||||
|
können aber trotzdem jederzeit von Dir gelöscht werden.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Desweiteren gibt es sogenannte Drittanbieter-Cookies. Cookies von Drittanbietern sind
|
||||||
|
Cookies, die durch eingebundene Funktionalitäten anderer Websites angelegt werden, zum
|
||||||
|
Beispiel bei Like-Buttons, Landkarten oder Videos-Plugins, obwohl Du nur unsere Website
|
||||||
|
besuchst. Diese Drittanbieter können dann Cookies lesen und speichern, genauso, als wenn
|
||||||
|
Du deren Seite besuchen würdest.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Da wir als Social-Network bestimmte Funktionalitäten, wie zum Beispiel eingebettete
|
||||||
|
Videos, für die Nutzer zur Verfügung stellen möchten, kommen wir ohne diese Cookies leider
|
||||||
|
nicht aus. Cookies von Drittanbietern ermöglichen das sogenannte Tracking. D.h., dass der
|
||||||
|
Drittanbieter über Deinen Aufruf unserer Website informiert wird und diese Daten auswerten
|
||||||
|
kann.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Auch diese Cookies können jederzeit gelöscht werden. Auch kannst Du im Browser das Setzen
|
||||||
|
von Drittanbietercookies verbieten. Dadurch wird unsere Website aber unter Umständen in
|
||||||
|
Ihrer Funktion eingeschränkt sein. Dein Browser kann auch so eingestellt werden, dass Du
|
||||||
|
über Cookies informiert wirst und das Speichern einzeln bestätigen oder ablehnen kannst.
|
||||||
|
Informationen zu den oft genutzten Browsern findest Du hier:
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Firefox:
|
||||||
|
<a
|
||||||
|
href="https://support.mozilla.org/de/kb/cookies-erlauben-und-ablehnen"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
https://support.mozilla.org/de/kb/cookies-erlauben-und-ablehnen
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Chrome:</strong>
|
||||||
|
<a
|
||||||
|
href="http://support.google.com/chrome/bin/answer.py?hl=de&hlrm=en&answer=95647"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
http://support.google.com/chrome/bin/answer.py?hl=de&hlrm=en&answer=95647
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Safari:</strong>
|
||||||
|
<a href="https://support.apple.com/kb/ph21411?locale=de_DE" target="_blank">
|
||||||
|
https://support.apple.com/kb/ph21411?locale=de_DE
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Opera:</strong>
|
||||||
|
<a href="http://help.opera.com/Windows/10.20/de/cookies.html" target="_blank">
|
||||||
|
http://help.opera.com/Windows/10.20/de/cookies.html
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Edge:</strong>
|
||||||
|
<a
|
||||||
|
href="https://privacy.microsoft.com/en-us/windows-10-microsoft-edge-and-privacy"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
https://privacy.microsoft.com/en-us/windows-10-microsoft-edge-and-privacy
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1>Die Öffentlichkeit</h1>
|
||||||
|
<p>
|
||||||
|
Unser Netzwerk und alle darin von Dir oder anderen veröffentlichten Daten stehen der
|
||||||
|
Öffentlichkeit zur Verfügung, solange Inhalte bzw. Funktionen nicht explizit anders
|
||||||
|
gekennzeichnet sind. Überdenke daher, was Du schreibst und wie Du Dich äußerst, denn was
|
||||||
|
einmal in der Öffentlichkeit ist, lässt sich nur schwer wieder zurücknehmen, selbst, wenn
|
||||||
|
Du oder wir es löschen.
|
||||||
|
</p>
|
||||||
|
<h1>Du hast Rechte</h1>
|
||||||
|
<p>
|
||||||
|
Damit Du unsere Webanwendung nutzen kannst, verarbeiten wir u.a. personenbezogene Daten
|
||||||
|
von Dir. Du bist also eine von dieser Verarbeitung „betroffene Person“. Gemäß der
|
||||||
|
europäischen Datenschutzgrundverordnung kannst Du daher uns gegenüber folgende Rechte
|
||||||
|
ausüben:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Auskunft über Deine ggf. bei uns verarbeiteten personenbezogenen Daten,</li>
|
||||||
|
<li>Berichtigung unrichtiger personenbezogener Daten,</li>
|
||||||
|
<li>Löschung Deiner bei uns gespeicherten personenbezogenen Daten,</li>
|
||||||
|
<li>
|
||||||
|
Einschränkung der Datenverarbeitung, sofern wir Deine Daten aufgrund gesetzlicher
|
||||||
|
Pflichten noch nicht löschen dürfen,
|
||||||
|
</li>
|
||||||
|
<li>Widerspruch gegen die Verarbeitung Deiner Daten bei uns und</li>
|
||||||
|
<li>Datenübertragbarkeit</li>
|
||||||
|
</ul>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
Sofern Du uns eine Einwilligung zur Verarbeitung Deiner personenbezogenen Daten erteilt
|
||||||
|
hast (bei der Registrierung), kannst Du diese jederzeit mit Wirkung für die Zukunft
|
||||||
|
widerrufen.
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
Du kannst Dich auch jederzeit bei einer Aufsichtsbehörde über uns beschweren, solltest
|
||||||
|
Du der Ansicht sein, dass die Verarbeitung Deiner personenbezogenen Daten gegen die
|
||||||
|
europäische Datenschutz-Grundverodnung oder das Bundesdatenschutzgesetz verstößt. Eine
|
||||||
|
Möglichkeit ist hier:
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
Landesbeauftragter für Datenschutz und Informationsfreiheit Baden-Württemberg
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="https://www.baden-wuerttemberg.datenschutz.de/kontakt/" target="_blank">
|
||||||
|
https://www.baden-wuerttemberg.datenschutz.de/kontakt/
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<h1>Verwendung von Youtube-Videos</h1>
|
||||||
|
<p>
|
||||||
|
Wir nutzen die Youtube-Einbettungsfunktion zur Anzeige und Wiedergabe von Videos des
|
||||||
|
Anbieters „Youtube“, der zu der Google LLC., 1600 Amphitheatre Parkway, Mountain View, CA
|
||||||
|
94043, USA („Google“) gehört.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Dabei wird der erweiterte Datenschutzmodus verwendet, der nach Angaben von Google eine
|
||||||
|
Speicherung von Nutzerinformationen erst bei Wiedergabe des/der Videos in Gang setzt.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Wenn Du die Wiedergabe eingebetteter Youtube-Videos startest, setzt der Google „Youtube“
|
||||||
|
Cookies ein, um Informationen über Dein Nutzungsverhalten zu sammeln. „Youtube“ nach
|
||||||
|
dienen diese unter anderem dazu, Videostatistiken zu erfassen, die Nutzerfreundlichkeit zu
|
||||||
|
verbessern und Missbrauch zu unterbinden. Bist Du gleichzeitig bei YouTube eingeloggt,
|
||||||
|
werden diese Informationen Deinem Mitgliedskonto bei YouTube zugeordnet. Wenn Du die
|
||||||
|
Zuordnung mit Deinem Profil bei YouTube nicht wünschst, musst Du Dich vor Aktivierung des
|
||||||
|
Buttons ausloggen. Google speichert Deine Daten (selbst für nicht eingeloggte Nutzer) als
|
||||||
|
Nutzungsprofile und wertet diese aus. Eine solche Auswertung erfolgt insbesondere gemäß
|
||||||
|
Art. 6 Abs. 1 lit.f DSGVO auf Basis der berechtigten Interessen von Google an der
|
||||||
|
Einblendung personalisierter Werbung, Marktforschung und/oder bedarfsgerechten Gestaltung
|
||||||
|
seiner Website. Dir steht ein Widerspruchsrecht zu gegen die Bildung dieser Nutzerprofile,
|
||||||
|
wobei Du Dich zur Ausübung dessen an YouTube richten musst.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Unabhängig von einer Wiedergabe der eingebetteten Videos wird bei jedem Aufruf dieser
|
||||||
|
Website eine Verbindung zum Google-Netzwerk „DoubleClick“ aufgenommen, was ohne unseren
|
||||||
|
Einfluss weitere Datenverarbeitungsvorgänge auslösen kann.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Google LLC mit Sitz in den USA ist für das us-europäische Datenschutzübereinkommen
|
||||||
|
„Privacy Shield“ zertifiziert, welches die Einhaltung des in der EU geltenden
|
||||||
|
Datenschutzniveaus gewährleistet.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Weitere Informationen zum Datenschutz bei „YouTube“ findest Du in der Datenschutzerklärung
|
||||||
|
des Anbieters unter:
|
||||||
|
<a href="https://www.google.de/intl/de/policies/privacy" target="_blank">
|
||||||
|
https://www.google.de/intl/de/policies/privacy
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<h1>Verwendung von Vimeo-Videos</h1>
|
||||||
|
<p>
|
||||||
|
Wir nutzen auch Plugins von Vimeo der Vimeo, LLC, 555 West 18th Street, New York, New York
|
||||||
|
10011, USA.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Rufst du eine Seite auf, die ein solches Plugin eingebunden hat, stellt Dein Browser eine
|
||||||
|
direkte Verbindung zu den Servern von Vimeo her. Durch diese Einbindung erhält Vimeo die
|
||||||
|
Information, dass Du unsere Seite aufgerufen hast, auch wenn Du keinen Vimeo-Account
|
||||||
|
besitzt oder gerade nicht bei Vimeo eingeloggt bist. Deine IP-Adresse und noch einige
|
||||||
|
Daten, die Dein Browser liefert, werden von Deinem Browser direkt an einen Server von
|
||||||
|
Vimeo in die USA übermittelt und dort gespeichert.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Wenn Du gerade bei Vimeo eingeloggt bist, kann Vimeo die Nutzung unserer webanwendung
|
||||||
|
Deinem Vimeo-Account zuordnen. Wenn Du das Plugin benutzt, wie z.B. beim Start eines
|
||||||
|
Videos, werden diese Informationen ebenso an einen Server von Vimeo gesendet und dort
|
||||||
|
verarbeitet.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Diese Verarbeitungsvorgänge erfolgen gem. Art. 6 Abs. 1 lit. f DSGVO auf Grundlage des
|
||||||
|
berechtigten Interesses von Vimeo an Marktforschung und der bedarfsgerechten Gestaltung
|
||||||
|
des Dienstes.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>Wenn Du das nicht möchtest, musst Du Dich vorher bei Vimeo ausloggen.</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Vimeo informiert über den Zweck, Umfang und die weitere Verarbeitung und Nutzung der
|
||||||
|
Daten, sowie Ihre diesbezüglichen Rechte und Einstellungsmöglichkeiten zum Schutz Deiner
|
||||||
|
Privatsphäre in den Datenschutzhinweisen:
|
||||||
|
<a href="https://vimeo.com/privacy" target="_blank">https://vimeo.com/privacy</a>
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Bei Vimeo-Videos, die bei uns in Beiträgen eingebunden sind, ist das Trackingtool Google
|
||||||
|
Analytics integriert. Auf dieses Tracking seitens Vimeo haben wir leider keinen Einfluss.
|
||||||
|
Google Analytics verwendet für das Tracking „Drittanbieter-Cookies“, wie schon oben
|
||||||
|
beschrieben. Die erhobenen Daten über Deine Benutzung unserer Website werden an einen
|
||||||
|
Server von Google übertragen und dort gespeichert, in der Regel in die USA.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
Dies erfolgt gem. Art. 6 Abs. 1 lit. f DSGVO auf Grundlage des berechtigten Interesses von
|
||||||
|
Vimeo an der statistischen Analyse des Nutzerverhaltens zu Optimierungs- und
|
||||||
|
Marketingzwecken.
|
||||||
|
</p>
|
||||||
|
<h1>Sicherheit des Web-Zugriffs</h1>
|
||||||
|
<p>
|
||||||
|
Um die Datenübertragung von unserem Webserver zu Dir und umgekehrt zu schützen, verwenden
|
||||||
|
wir eine TLS 1.3 verschlüsselte Verbindung. Dass erkennst Du am grünen Schloss in Deinem
|
||||||
|
Browser bzw. daran, dass Deine URL mit „https“ beginnt, statt mit „http“. So kann niemand
|
||||||
|
mitlesen, was Du siehst oder was Du eingibst.
|
||||||
|
</p>
|
||||||
|
</ds-space>
|
||||||
|
</ds-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
layout: 'default',
|
||||||
|
head() {
|
||||||
|
return {
|
||||||
|
title: this.$t('site.data-privacy'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -23,9 +23,7 @@
|
|||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
|
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
|
||||||
<ds-space margin="small">
|
<ds-space margin="small">
|
||||||
<ds-text size="small">
|
<ds-text size="small">{{ $t('login.copy') }}</ds-text>
|
||||||
{{ $t('login.copy') }}
|
|
||||||
</ds-text>
|
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<form :disabled="pending" @submit.prevent="onSubmit">
|
<form :disabled="pending" @submit.prevent="onSubmit">
|
||||||
<ds-input
|
<ds-input
|
||||||
@ -46,9 +44,7 @@
|
|||||||
type="password"
|
type="password"
|
||||||
/>
|
/>
|
||||||
<ds-space class="password-reset-link" margin-bottom="large">
|
<ds-space class="password-reset-link" margin-bottom="large">
|
||||||
<nuxt-link to="/password-reset/request">
|
<nuxt-link to="/password-reset/request">{{ $t('login.forgotPassword') }}</nuxt-link>
|
||||||
{{ $t('login.forgotPassword') }}
|
|
||||||
</nuxt-link>
|
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-button
|
<ds-button
|
||||||
:loading="pending"
|
:loading="pending"
|
||||||
@ -84,7 +80,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
LocaleSwitch,
|
LocaleSwitch,
|
||||||
},
|
},
|
||||||
layout: 'blank',
|
layout: 'default',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ready: false,
|
ready: false,
|
||||||
|
|||||||
@ -6,9 +6,7 @@
|
|||||||
<img style="width: 200px;" src="/img/sign-up/onourjourney.png" alt="Human Connection" />
|
<img style="width: 200px;" src="/img/sign-up/onourjourney.png" alt="Human Connection" />
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-space style="text-align: center;" margin-top="small" margin-bottom="xxx-small" centered>
|
<ds-space style="text-align: center;" margin-top="small" margin-bottom="xxx-small" centered>
|
||||||
<ds-heading tag="h3" soft>
|
<ds-heading tag="h3" soft>Logging out...</ds-heading>
|
||||||
Logging out...
|
|
||||||
</ds-heading>
|
|
||||||
</ds-space>
|
</ds-space>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
@ -17,7 +15,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
layout: 'blank',
|
layout: 'default',
|
||||||
async beforeCreate() {
|
async beforeCreate() {
|
||||||
await this.$store.dispatch('auth/logout')
|
await this.$store.dispatch('auth/logout')
|
||||||
this.$router.replace('/')
|
this.$router.replace('/')
|
||||||
|
|||||||
@ -20,10 +20,7 @@
|
|||||||
<ds-space margin-bottom="small" />
|
<ds-space margin-bottom="small" />
|
||||||
<ds-heading tag="h3" no-margin>{{ post.title }}</ds-heading>
|
<ds-heading tag="h3" no-margin>{{ post.title }}</ds-heading>
|
||||||
<ds-space margin-bottom="small" />
|
<ds-space margin-bottom="small" />
|
||||||
<!-- Content -->
|
<content-viewer class="content" :content="post.content" />
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
|
||||||
<!-- TODO: replace editor content with tiptap render view -->
|
|
||||||
<div class="content hc-editor-content" v-html="post.content" />
|
|
||||||
<!-- eslint-enable vue/no-v-html -->
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
<ds-space margin="xx-large" />
|
<ds-space margin="xx-large" />
|
||||||
<!-- Categories -->
|
<!-- Categories -->
|
||||||
@ -62,6 +59,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ContentViewer from '~/components/Editor/ContentViewer'
|
||||||
import HcCategory from '~/components/Category'
|
import HcCategory from '~/components/Category'
|
||||||
import HcTag from '~/components/Tag'
|
import HcTag from '~/components/Tag'
|
||||||
import ContentMenu from '~/components/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu'
|
||||||
@ -86,6 +84,7 @@ export default {
|
|||||||
ContentMenu,
|
ContentMenu,
|
||||||
HcCommentForm,
|
HcCommentForm,
|
||||||
HcCommentList,
|
HcCommentList,
|
||||||
|
ContentViewer,
|
||||||
},
|
},
|
||||||
head() {
|
head() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<ds-space>
|
|
||||||
<ds-heading tag="h2">{{ $t('site.privacy') }}</ds-heading>
|
|
||||||
</ds-space>
|
|
||||||
<ds-container>
|
|
||||||
<ds-space margin-top="large">
|
|
||||||
<ds-text>{{ $t('site.privacy') }}</ds-text>
|
|
||||||
<ds-text>...</ds-text>
|
|
||||||
</ds-space>
|
|
||||||
</ds-container>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
head() {
|
|
||||||
return {
|
|
||||||
title: this.$t('site.privacy'),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -1,22 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ds-space>
|
<ds-space>
|
||||||
<ds-heading tag="h2">{{ $t('site.termsAc') }}</ds-heading>
|
<ds-heading tag="h2">{{ $t('site.termsAndConditions') }}</ds-heading>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<ds-container>
|
<ds-container>
|
||||||
<ds-space margin-top="large">
|
<div>
|
||||||
<ds-text>{{ $t('site.termsAc') }}</ds-text>
|
<ol>
|
||||||
<ds-text v-html="$t('terms.text')"></ds-text>
|
<li v-for="section in sections" :key="section">
|
||||||
</ds-space>
|
<strong>{{ $t(`termsAndConditions.${section}.title`) }}:</strong>
|
||||||
|
<p v-html="$t(`termsAndConditions.${section}.description`)" />
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p>{{ $t('termsAndConditions.have-fun') }}</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<strong v-html="$t('termsAndConditions.closing')" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</ds-container>
|
</ds-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
layout: 'default',
|
||||||
head() {
|
head() {
|
||||||
return {
|
return {
|
||||||
title: this.$t('site.termsAc'),
|
title: this.$t('site.termsAndConditions'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sections: [
|
||||||
|
'risk',
|
||||||
|
'data-privacy',
|
||||||
|
'work-in-progress',
|
||||||
|
'code-of-conduct',
|
||||||
|
'moderation',
|
||||||
|
'fairness',
|
||||||
|
'questions',
|
||||||
|
'human-connection',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
4
webapp/plugins/vue-sweetalert-icons.js
Normal file
4
webapp/plugins/vue-sweetalert-icons.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueSweetalertIcons from 'vue-sweetalert-icons'
|
||||||
|
|
||||||
|
Vue.use(VueSweetalertIcons)
|
||||||
3
webapp/storybook/addons.js
Normal file
3
webapp/storybook/addons.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import '@storybook/addon-actions/register'
|
||||||
|
import '@storybook/addon-a11y/register'
|
||||||
|
// import '@storybook/addon-links/register'
|
||||||
32
webapp/storybook/config.js
Normal file
32
webapp/storybook/config.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { configure } from '@storybook/vue'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { action } from '@storybook/addon-actions'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
Vue.component('nuxt-link', {
|
||||||
|
props: ['to'],
|
||||||
|
methods: {
|
||||||
|
log() {
|
||||||
|
action('link clicked')(this.to)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: '<a href="#" @click.prevent="log()"><slot>NuxtLink</slot></a>',
|
||||||
|
})
|
||||||
|
Vue.component('no-ssr', {
|
||||||
|
render() {
|
||||||
|
return this.$slots.default
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Vue.component('v-popover', {
|
||||||
|
template: '<div><slot>Popover Content</slot></div>',
|
||||||
|
})
|
||||||
|
|
||||||
|
// Automatically import all files ending in *.stories.js
|
||||||
|
const req = require.context('../components', true, /.story.js$/)
|
||||||
|
|
||||||
|
function loadStories() {
|
||||||
|
req.keys().forEach(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
configure(loadStories, module)
|
||||||
57
webapp/storybook/helpers.js
Normal file
57
webapp/storybook/helpers.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import vuexI18n from 'vuex-i18n/dist/vuex-i18n.umd.js'
|
||||||
|
import Styleguide from '@human-connection/styleguide'
|
||||||
|
import Filters from '~/plugins/vue-filters'
|
||||||
|
import layout from './layout.vue'
|
||||||
|
|
||||||
|
const helpers = {
|
||||||
|
init(options = {}) {
|
||||||
|
Vue.use(Vuex)
|
||||||
|
Vue.use(Styleguide)
|
||||||
|
Vue.use(Filters)
|
||||||
|
|
||||||
|
Vue.use(vuexI18n.plugin, helpers.store)
|
||||||
|
Vue.i18n.add('en', require('~/locales/en.json'))
|
||||||
|
Vue.i18n.add('de', require('~/locales/de.json'))
|
||||||
|
Vue.i18n.set('en')
|
||||||
|
Vue.i18n.fallback('en')
|
||||||
|
|
||||||
|
const { plugins = [] } = options
|
||||||
|
plugins.forEach(plugin => Vue.use(plugin))
|
||||||
|
},
|
||||||
|
store: new Vuex.Store({
|
||||||
|
modules: {
|
||||||
|
auth: {
|
||||||
|
namespaced: true,
|
||||||
|
getters: {
|
||||||
|
user(state) {
|
||||||
|
return { id: 1, name: 'admin' }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
namespaced: true,
|
||||||
|
getters: {
|
||||||
|
placeholder(state) {
|
||||||
|
return 'Leave your inspirational thoughts...'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
layout(storyFn) {
|
||||||
|
const ctx = storyFn()
|
||||||
|
return {
|
||||||
|
components: { ctx, layout },
|
||||||
|
template: `
|
||||||
|
<layout>
|
||||||
|
<ds-flex>
|
||||||
|
<ctx />
|
||||||
|
</ds-flex>
|
||||||
|
</layout>`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default helpers
|
||||||
14
webapp/storybook/layout.vue
Normal file
14
webapp/storybook/layout.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<ds-container class="container">
|
||||||
|
<slot />
|
||||||
|
</ds-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../node_modules/@human-connection/styleguide/dist/system.css';
|
||||||
|
@import '~/assets/styles/main.scss';
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
43
webapp/storybook/webpack.config.js
Normal file
43
webapp/storybook/webpack.config.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const nuxtConf = require('../nuxt.config')
|
||||||
|
const srcDir = `../${nuxtConf.srcDir || ''}`
|
||||||
|
const rootDir = `../${nuxtConf.rootDir || ''}`
|
||||||
|
|
||||||
|
// Export a function. Accept the base config as the only param.
|
||||||
|
module.exports = async ({ config, mode }) => {
|
||||||
|
// `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||||
|
// You can change the configuration based on that.
|
||||||
|
// 'PRODUCTION' is used when building the static version of storybook.
|
||||||
|
|
||||||
|
// Make whatever fine-grained changes you need
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [
|
||||||
|
{ loader: 'style-loader' },
|
||||||
|
{ loader: 'css-loader', options: { sourceMap: true } },
|
||||||
|
{ loader: 'sass-loader', options: { sourceMap: true } },
|
||||||
|
{
|
||||||
|
loader: 'style-resources-loader',
|
||||||
|
options: {
|
||||||
|
patterns: [
|
||||||
|
path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'../node_modules/@human-connection/styleguide/dist/shared.scss',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
injector: 'prepend',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
include: path.resolve(__dirname, '../'),
|
||||||
|
})
|
||||||
|
|
||||||
|
config.resolve.alias = {
|
||||||
|
...config.resolve.alias,
|
||||||
|
'~~': path.resolve(__dirname, rootDir),
|
||||||
|
'~': path.resolve(__dirname, srcDir),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the altered config
|
||||||
|
return config
|
||||||
|
}
|
||||||
2583
webapp/yarn.lock
2583
webapp/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -3579,10 +3579,10 @@ neo4j-driver@^1.6.3, neo4j-driver@^1.7.5:
|
|||||||
text-encoding-utf-8 "^1.0.2"
|
text-encoding-utf-8 "^1.0.2"
|
||||||
uri-js "^4.2.2"
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
neode@^0.3.0:
|
neode@^0.3.1:
|
||||||
version "0.3.0"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/neode/-/neode-0.3.0.tgz#a4a41234fac23236db6b589ec2b505ad6e5fd832"
|
resolved "https://registry.yarnpkg.com/neode/-/neode-0.3.1.tgz#d40147bf20d6951b69c9d392fbdd322aeca07816"
|
||||||
integrity sha512-V6uQhap7FDwbeC+mH6JEI352QSou4Ukj7vs/bGZSrVlMZKVS8vs/mbQYXoFdCkmQJuUtJWqO9wmtWg5GjCaNDQ==
|
integrity sha512-SdaJmdjQ3PWOH6W1H8Xgd2CLyJs+BPPXPt0jOVNs7naeQH8nWPP6ixDqI6NWDCxwecTdNl//fpAicB9I6hCwEw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@hapi/joi" "^15.1.0"
|
"@hapi/joi" "^15.1.0"
|
||||||
dotenv "^4.0.0"
|
dotenv "^4.0.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user