mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merged master in
This commit is contained in:
commit
5b33257f5a
16
.babelrc
16
.babelrc
@ -1,11 +1,23 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", { "modules": false }]
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": false
|
||||
}
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [
|
||||
["env", { "targets": { "node": "current" }}]
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "10"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.vscode/
|
||||
|
||||
styleguide/node_modules/
|
||||
styleguide/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,6 +30,7 @@ build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
styleguide/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
@ -79,6 +80,7 @@ static/uploads
|
||||
|
||||
cypress/videos
|
||||
cypress/screenshots/
|
||||
cypress.env.json
|
||||
|
||||
# Apple macOS folder attribute file
|
||||
.DS_Store
|
||||
|
||||
14
.travis.yml
14
.travis.yml
@ -18,27 +18,33 @@ before_install:
|
||||
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin
|
||||
- cp cypress.env.template.json cypress.env.json
|
||||
|
||||
install:
|
||||
- docker build --build-arg BUILD_COMMIT=$TRAVIS_COMMIT --target production -t humanconnection/nitro-web .
|
||||
- docker-compose -f docker-compose.yml -f docker-compose.travis.yml up -d
|
||||
- git clone https://github.com/Human-Connection/Nitro-Backend.git ../Nitro-Backend
|
||||
- git -C "../Nitro-Backend" checkout $BACKEND_BRANCH || git -C "../Nitro-Backend" checkout master
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml -f ../Nitro-Backend/docker-compose.travis.yml up -d
|
||||
- cd ../Nitro-Backend && yarn install && cd -
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml -f ../Nitro-Backend/docker-compose.cypress.yml up -d
|
||||
- yarn global add cypress wait-on
|
||||
- yarn add cypress-cucumber-preprocessor
|
||||
|
||||
script:
|
||||
- docker-compose exec -e NODE_ENV=test webapp yarn run lint
|
||||
- docker-compose exec -e NODE_ENV=test webapp yarn run test
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml exec backend yarn run db:seed
|
||||
- wait-on http://localhost:3000
|
||||
- cypress run --record --key $CYPRESS_TOKEN
|
||||
- wait-on http://localhost:7474 && docker-compose -f ../Nitro-Backend/docker-compose.yml exec neo4j migrate
|
||||
- wait-on http://localhost:3000 && cypress run --record --key $CYPRESS_TOKEN
|
||||
|
||||
after_success:
|
||||
- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
|
||||
- chmod +x send.sh
|
||||
- ./send.sh success $WEBHOOK_URL
|
||||
- if [ $TRAVIS_BRANCH == "master" ] && [ $TRAVIS_EVENT_TYPE == "push" ]; then
|
||||
wget https://raw.githubusercontent.com/Human-Connection/Discord-Bot/develop/tester.sh &&
|
||||
chmod +x tester.sh &&
|
||||
./tester.sh staging $WEBHOOK_URL;
|
||||
fi
|
||||
|
||||
after_failure:
|
||||
- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
|
||||
|
||||
@ -19,9 +19,6 @@ COPY . .
|
||||
FROM base as build-and-test
|
||||
RUN cp .env.template .env
|
||||
RUN yarn install --production=false --frozen-lockfile --non-interactive
|
||||
RUN cd styleguide && yarn install --production=false --frozen-lockfile --non-interactive \
|
||||
&& cd .. \
|
||||
&& yarn run styleguide:build
|
||||
RUN yarn run build
|
||||
|
||||
FROM base as production
|
||||
|
||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Human-Connection gGmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
26
README.md
26
README.md
@ -1,5 +1,12 @@
|
||||
# Human Connection - NITRO Web
|
||||
[](https://travis-ci.com/Human-Connection/Nitro-Web)
|
||||
<p align="center">
|
||||
<a href="https://human-connection.org"><img align="center" src="static/img/sign-up/humanconnection.png" height="200" alt="Human Connection" /></a>
|
||||
</p>
|
||||
|
||||
# NITRO Web
|
||||
[](https://travis-ci.com/Human-Connection/Nitro-Web)
|
||||
[](https://github.com/Human-Connection/Nitro-Web/blob/master/LICENSE.md)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web?ref=badge_shield)
|
||||
[](https://discord.gg/6ub73U3)
|
||||
|
||||

|
||||
|
||||
@ -10,16 +17,15 @@
|
||||
### Install
|
||||
``` bash
|
||||
# install all dependencies
|
||||
$ cd styleguide && yarn install && cd ..
|
||||
$ yarn styleguide:build
|
||||
$ yarn install
|
||||
```
|
||||
|
||||
Copy:
|
||||
```
|
||||
cp .env.template .env
|
||||
cp cypress.env.template.json cypress.env.json
|
||||
```
|
||||
Configure the file `.env` according to your needs and your local setup.
|
||||
Configure the files according to your needs and your local setup.
|
||||
|
||||
### Development
|
||||
``` bash
|
||||
@ -30,7 +36,6 @@ $ yarn dev
|
||||
### Build for production
|
||||
``` bash
|
||||
# build for production and launch server
|
||||
$ yarn styleguide:build
|
||||
$ yarn build
|
||||
$ yarn start
|
||||
```
|
||||
@ -41,10 +46,8 @@ All reusable Components (for example avatar) should be done inside the styleguid
|
||||
|
||||

|
||||
|
||||
### To show the styleguide
|
||||
``` bash
|
||||
$ yarn styleguide
|
||||
```
|
||||
More information can be found here: https://github.com/Human-Connection/Nitro-Styleguide
|
||||
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
@ -57,3 +60,6 @@ Thanks lokalise.co that we can use your premium account!
|
||||
## Attributions
|
||||
|
||||
<div>Locale Icons made by <a href="http://www.freepik.com/" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
|
||||
|
||||
## License
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web?ref=badge_large)
|
||||
|
||||
@ -78,45 +78,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
.hc-editor-content {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
&:not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
p {
|
||||
&:not(:last-child) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
dl,
|
||||
ol,
|
||||
ul,
|
||||
blockquote,
|
||||
pre,
|
||||
table {
|
||||
&:not(:first-child) {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
*:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
// avoid double breaks
|
||||
br + p {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
|
||||
@ -8,14 +8,19 @@
|
||||
slot="default"
|
||||
slot-scope="{toggleMenu}"
|
||||
>
|
||||
<ds-button
|
||||
class="content-menu-trigger"
|
||||
size="small"
|
||||
ghost
|
||||
@click.prevent="toggleMenu"
|
||||
<slot
|
||||
name="button"
|
||||
:toggleMenu="toggleMenu"
|
||||
>
|
||||
<ds-icon name="ellipsis-v" />
|
||||
</ds-button>
|
||||
<ds-button
|
||||
class="content-menu-trigger"
|
||||
size="small"
|
||||
ghost
|
||||
@click.prevent="toggleMenu"
|
||||
>
|
||||
<ds-icon name="ellipsis-v" />
|
||||
</ds-button>
|
||||
</slot>
|
||||
</template>
|
||||
<div
|
||||
slot="popover"
|
||||
@ -49,6 +54,7 @@ export default {
|
||||
placement: { type: String, default: 'top-end' },
|
||||
itemId: { type: String, required: true },
|
||||
name: { type: String, required: true },
|
||||
isOwner: { type: Boolean, default: false },
|
||||
context: {
|
||||
type: String,
|
||||
required: true,
|
||||
@ -59,20 +65,54 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
routes() {
|
||||
let routes = [
|
||||
{
|
||||
let routes = []
|
||||
|
||||
if (this.isOwner && this.context === 'contribution') {
|
||||
routes.push({
|
||||
name: this.$t(`contribution.edit`),
|
||||
path: this.$router.resolve({
|
||||
name: 'post-edit-id',
|
||||
params: {
|
||||
id: this.itemId
|
||||
}
|
||||
}).href,
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
if (this.isOwner && this.context === 'comment') {
|
||||
routes.push({
|
||||
name: this.$t(`comment.edit`),
|
||||
callback: () => {
|
||||
console.log('EDIT COMMENT')
|
||||
},
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.isOwner) {
|
||||
routes.push({
|
||||
name: this.$t(`report.${this.context}.title`),
|
||||
callback: this.openReportDialog,
|
||||
icon: 'flag'
|
||||
}
|
||||
]
|
||||
if (this.isModerator) {
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.isOwner && this.isModerator) {
|
||||
routes.push({
|
||||
name: this.$t(`disable.${this.context}.title`),
|
||||
callback: this.openDisableDialog,
|
||||
callback: () => {},
|
||||
icon: 'eye-slash'
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isOwner && this.context === 'user') {
|
||||
routes.push({
|
||||
name: this.$t(`settings.data.name`),
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
callback: () => this.$router.push('/settings'),
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
return routes
|
||||
},
|
||||
isModerator() {
|
||||
|
||||
145
components/ContributionForm.vue
Normal file
145
components/ContributionForm.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<ds-form
|
||||
ref="contributionForm"
|
||||
v-model="form"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
>
|
||||
<template slot-scope="{ errors }">
|
||||
<ds-card>
|
||||
<ds-input
|
||||
model="title"
|
||||
class="post-title"
|
||||
placeholder="Title"
|
||||
name="title"
|
||||
autofocus
|
||||
/>
|
||||
<no-ssr>
|
||||
<hc-editor
|
||||
:value="form.content"
|
||||
@input="updateEditorContent"
|
||||
/>
|
||||
</no-ssr>
|
||||
<div
|
||||
slot="footer"
|
||||
style="text-align: right"
|
||||
>
|
||||
<ds-button
|
||||
:disabled="loading || disabled"
|
||||
ghost
|
||||
@click.prevent="$router.back()"
|
||||
>
|
||||
{{ $t('actions.cancel') }}
|
||||
</ds-button>
|
||||
<ds-button
|
||||
icon="check"
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
:disabled="disabled || errors"
|
||||
primary
|
||||
>
|
||||
{{ $t('actions.save') }}
|
||||
</ds-button>
|
||||
</div>
|
||||
</ds-card>
|
||||
</template>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcEditor from '~/components/Editor/Editor.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcEditor
|
||||
},
|
||||
props: {
|
||||
contribution: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
formSchema: {
|
||||
title: { required: true, min: 3, max: 64 },
|
||||
content: { required: true, min: 3 }
|
||||
},
|
||||
id: null,
|
||||
loading: false,
|
||||
disabled: false,
|
||||
slug: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
contribution: {
|
||||
immediate: true,
|
||||
handler: function(contribution) {
|
||||
if (!contribution || !contribution.id) {
|
||||
return
|
||||
}
|
||||
this.id = contribution.id
|
||||
this.slug = contribution.slug
|
||||
this.form.content = contribution.content
|
||||
this.form.title = contribution.title
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
const postMutations = require('~/graphql/PostMutations.js').default(this)
|
||||
this.loading = true
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: this.id
|
||||
? postMutations.UpdatePost
|
||||
: postMutations.CreatePost,
|
||||
variables: {
|
||||
id: this.id,
|
||||
title: this.form.title,
|
||||
content: this.form.content
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
this.loading = false
|
||||
this.$toast.success('Saved!')
|
||||
this.disabled = true
|
||||
|
||||
const result = res.data[this.id ? 'UpdatePost' : 'CreatePost']
|
||||
|
||||
this.$router.push({
|
||||
name: 'post-slug',
|
||||
params: { slug: result.slug }
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
this.$toast.error(err.message)
|
||||
this.loading = false
|
||||
this.disabled = false
|
||||
})
|
||||
},
|
||||
updateEditorContent(value) {
|
||||
// this.form.content = value
|
||||
this.$refs.contributionForm.update('content', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.post-title {
|
||||
margin-top: $space-x-small;
|
||||
margin-bottom: $space-xx-small;
|
||||
|
||||
input {
|
||||
border: 0;
|
||||
font-size: $font-size-x-large;
|
||||
font-weight: bold;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
366
components/Editor/Editor.vue
Normal file
366
components/Editor/Editor.vue
Normal file
@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<div class="editor">
|
||||
<editor-menu-bubble :editor="editor">
|
||||
<div
|
||||
ref="menu"
|
||||
slot-scope="{ commands, getMarkAttrs, isActive, menu }"
|
||||
class="menububble tooltip"
|
||||
x-placement="top"
|
||||
:class="{ 'is-active': menu.isActive || linkMenuIsActive }"
|
||||
:style="`left: ${menu.left}px; bottom: ${menu.bottom}px;`"
|
||||
>
|
||||
<div class="tooltip-wrapper">
|
||||
<template v-if="linkMenuIsActive">
|
||||
<ds-input
|
||||
ref="linkInput"
|
||||
v-model="linkUrl"
|
||||
class="editor-menu-link-input"
|
||||
placeholder="http://"
|
||||
@blur.native.capture="hideMenu(menu.isActive)"
|
||||
@keydown.native.esc.prevent="hideMenu(menu.isActive)"
|
||||
@keydown.native.enter.prevent="setLinkUrl(commands.link, linkUrl)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.bold()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="commands.bold"
|
||||
>
|
||||
<ds-icon name="bold" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.italic()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="commands.italic"
|
||||
>
|
||||
<ds-icon name="italic" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.link()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="showLinkMenu(getMarkAttrs('link'))"
|
||||
>
|
||||
<ds-icon name="link" />
|
||||
</ds-button>
|
||||
</template>
|
||||
</div>
|
||||
<div class="tooltip-arrow" />
|
||||
</div>
|
||||
</editor-menu-bubble>
|
||||
<editor-floating-menu :editor="editor">
|
||||
<div
|
||||
slot-scope="{ commands, isActive, menu }"
|
||||
class="editor__floating-menu"
|
||||
:class="{ 'is-active': menu.isActive }"
|
||||
:style="`top: ${menu.top}px`"
|
||||
>
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.paragraph()"
|
||||
@click.prevent="commands.paragraph()"
|
||||
>
|
||||
<ds-icon name="paragraph" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 3 })"
|
||||
@click.prevent="commands.heading({ level: 3 })"
|
||||
>
|
||||
H3
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 4 })"
|
||||
@click.prevent="commands.heading({ level: 4 })"
|
||||
>
|
||||
H4
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.bullet_list()"
|
||||
@click.prevent="commands.bullet_list()"
|
||||
>
|
||||
<ds-icon name="list-ul" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.ordered_list()"
|
||||
@click.prevent="commands.ordered_list()"
|
||||
>
|
||||
<ds-icon name="list-ol" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.blockquote()"
|
||||
@click.prevent="commands.blockquote"
|
||||
>
|
||||
<ds-icon name="quote-right" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.horizontal_rule()"
|
||||
@click.prevent="commands.horizontal_rule"
|
||||
>
|
||||
<ds-icon name="minus" />
|
||||
</ds-button>
|
||||
</div>
|
||||
</editor-floating-menu>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import linkify from 'linkify-it'
|
||||
import stringHash from 'string-hash'
|
||||
import {
|
||||
Editor,
|
||||
EditorContent,
|
||||
EditorFloatingMenu,
|
||||
EditorMenuBubble
|
||||
} from 'tiptap'
|
||||
import EventHandler from './plugins/eventHandler.js'
|
||||
import {
|
||||
Heading,
|
||||
HardBreak,
|
||||
Blockquote,
|
||||
ListItem,
|
||||
BulletList,
|
||||
OrderedList,
|
||||
HorizontalRule,
|
||||
Placeholder,
|
||||
Bold,
|
||||
Italic,
|
||||
Strike,
|
||||
Underline,
|
||||
Link,
|
||||
History
|
||||
} from 'tiptap-extensions'
|
||||
|
||||
let throttleInputEvent
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
EditorFloatingMenu,
|
||||
EditorMenuBubble
|
||||
},
|
||||
props: {
|
||||
value: { type: String, default: '' },
|
||||
doc: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lastValueHash: null,
|
||||
editor: new Editor({
|
||||
content: this.value || '',
|
||||
doc: this.doc,
|
||||
extensions: [
|
||||
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: 'Schreib etwas inspirerendes…'
|
||||
}),
|
||||
new History()
|
||||
],
|
||||
onUpdate: e => {
|
||||
clearTimeout(throttleInputEvent)
|
||||
throttleInputEvent = setTimeout(() => this.onUpdate(e), 300)
|
||||
}
|
||||
}),
|
||||
linkUrl: null,
|
||||
linkMenuIsActive: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler: function(content, old) {
|
||||
const contentHash = stringHash(content)
|
||||
if (!content || contentHash === this.lastValueHash) {
|
||||
return
|
||||
}
|
||||
this.lastValueHash = contentHash
|
||||
this.editor.setContent(content)
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
methods: {
|
||||
onUpdate(e) {
|
||||
const content = e.getHTML()
|
||||
const contentHash = stringHash(content)
|
||||
if (contentHash !== this.lastValueHash) {
|
||||
this.lastValueHash = contentHash
|
||||
this.$emit('input', content)
|
||||
}
|
||||
},
|
||||
showLinkMenu(attrs) {
|
||||
this.linkUrl = attrs.href
|
||||
this.linkMenuIsActive = true
|
||||
this.$nextTick(() => {
|
||||
try {
|
||||
const $el = this.$refs.linkInput.$el.getElementsByTagName('input')[0]
|
||||
$el.focus()
|
||||
$el.select()
|
||||
} catch (err) {}
|
||||
})
|
||||
},
|
||||
hideLinkMenu() {
|
||||
this.linkUrl = null
|
||||
this.linkMenuIsActive = false
|
||||
this.editor.focus()
|
||||
},
|
||||
hideMenu(isActive) {
|
||||
isActive = false
|
||||
this.hideLinkMenu()
|
||||
},
|
||||
setLinkUrl(command, url) {
|
||||
const links = linkify().match(url)
|
||||
if (links) {
|
||||
// add valid link
|
||||
command({
|
||||
href: links.pop().url
|
||||
})
|
||||
this.hideLinkMenu()
|
||||
this.editor.focus()
|
||||
} else if (!url) {
|
||||
// remove link
|
||||
command({ href: null })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ProseMirror {
|
||||
padding: $space-base;
|
||||
margin: -$space-base;
|
||||
min-height: $space-large;
|
||||
}
|
||||
|
||||
.ProseMirror:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.editor p.is-empty:first-child::before {
|
||||
content: attr(data-empty-text);
|
||||
float: left;
|
||||
color: $text-color-disabled;
|
||||
padding-left: $space-xx-small;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.menubar__button {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
li > p {
|
||||
margin-top: $space-xx-small;
|
||||
margin-bottom: $space-xx-small;
|
||||
}
|
||||
|
||||
.editor {
|
||||
&__floating-menu {
|
||||
position: absolute;
|
||||
margin-top: -0.25rem;
|
||||
margin-left: $space-xx-small;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
background-color: #fff;
|
||||
|
||||
&.is-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
.menububble {
|
||||
position: absolute;
|
||||
// margin-top: -0.5rem;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 200ms, visibility 200ms;
|
||||
// transition-delay: 50ms;
|
||||
transform: translate(-50%, -10%);
|
||||
|
||||
background-color: $background-color-inverse-soft;
|
||||
// color: $text-color-inverse;
|
||||
border-radius: $border-radius-base;
|
||||
padding: $space-xx-small;
|
||||
box-shadow: $box-shadow-large;
|
||||
|
||||
.ds-button {
|
||||
color: $text-color-inverse;
|
||||
|
||||
&.ds-button-hover,
|
||||
&:hover {
|
||||
color: $text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
left: calc(50% - 10px);
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.ds-input {
|
||||
height: auto;
|
||||
}
|
||||
input {
|
||||
padding: $space-xx-small $space-x-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
83
components/Editor/plugins/eventHandler.js
Normal file
83
components/Editor/plugins/eventHandler.js
Normal file
@ -0,0 +1,83 @@
|
||||
import { Extension, Plugin } from 'tiptap'
|
||||
// import { Slice, Fragment } from 'prosemirror-model'
|
||||
|
||||
export default class EventHandler extends Extension {
|
||||
get name() {
|
||||
return 'event_handler'
|
||||
}
|
||||
get plugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
transformPastedText(text) {
|
||||
// console.log('#### transformPastedText', text)
|
||||
return text.trim()
|
||||
},
|
||||
transformPastedHTML(html) {
|
||||
html = html
|
||||
// remove all tags with "space only"
|
||||
.replace(/<[a-z-]+>[\s]+<\/[a-z-]+>/gim, '')
|
||||
// remove all iframes
|
||||
.replace(
|
||||
/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/gim,
|
||||
''
|
||||
)
|
||||
.replace(/[\n]{3,}/gim, '\n\n')
|
||||
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
||||
|
||||
// replace all p tags with line breaks (and spaces) only by single linebreaks
|
||||
// limit linebreaks to max 2 (equivalent to html "br" linebreak)
|
||||
.replace(/(<br ?\/?>\s*){2,}/gim, '<br>')
|
||||
// remove additional linebreaks after p tags
|
||||
.replace(
|
||||
/<\/(p|div|th|tr)>\s*(<br ?\/?>\s*)+\s*<(p|div|th|tr)>/gim,
|
||||
'</p><p>'
|
||||
)
|
||||
// remove additional linebreaks inside p tags
|
||||
.replace(
|
||||
/<[a-z-]+>(<[a-z-]+>)*\s*(<br ?\/?>\s*)+\s*(<\/[a-z-]+>)*<\/[a-z-]+>/gim,
|
||||
''
|
||||
)
|
||||
// remove additional linebreaks when first child inside p tags
|
||||
.replace(/<p>(\s*<br ?\/?>\s*)+/gim, '<p>')
|
||||
// remove additional linebreaks when last child inside p tags
|
||||
.replace(/(\s*<br ?\/?>\s*)+<\/p>/gim, '</p>')
|
||||
// console.log('#### transformPastedHTML', html)
|
||||
return html
|
||||
}
|
||||
// transformPasted(slice) {
|
||||
// // console.log('#### transformPasted', slice.content)
|
||||
// let content = []
|
||||
// let size = 0
|
||||
// slice.content.forEach((node, offset, index) => {
|
||||
// // console.log(node)
|
||||
// // console.log('isBlock', node.type.isBlock)
|
||||
// // console.log('childCount', node.content.childCount)
|
||||
// // console.log('index', index)
|
||||
// if (node.content.childCount) {
|
||||
// content.push(node.content)
|
||||
// size += node.content.size
|
||||
// }
|
||||
// })
|
||||
// console.log(content)
|
||||
// console.log(slice.content)
|
||||
// let fragment = Fragment.fromArray(content)
|
||||
// fragment.size = size
|
||||
// console.log('#fragment', fragment, slice.content)
|
||||
// console.log('----')
|
||||
// console.log('#1', slice)
|
||||
// // const newSlice = new Slice(fragment, slice.openStart, slice.openEnd)
|
||||
// slice.fragment = fragment
|
||||
// // slice.content.content = fragment.content
|
||||
// // slice.content.size = fragment.size
|
||||
// console.log('#2', slice)
|
||||
// // console.log(newSlice)
|
||||
// console.log('----')
|
||||
// return slice
|
||||
// // return newSlice
|
||||
// }
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -55,6 +55,7 @@
|
||||
context="contribution"
|
||||
:item-id="post.id"
|
||||
:name="post.title"
|
||||
:is-owner="isAuthor"
|
||||
/>
|
||||
</no-ssr>
|
||||
</div>
|
||||
@ -86,13 +87,16 @@ export default {
|
||||
computed: {
|
||||
excerpt() {
|
||||
// remove all links from excerpt to prevent issues with the serounding link
|
||||
let excerpt = this.post.contentExcerpt.replace(/<a.*>(.+)<\/a>/gim, '')
|
||||
let excerpt = this.post.contentExcerpt.replace(/<a.*>(.+)<\/a>/gim, '$1')
|
||||
// do not display content that is only linebreaks
|
||||
if (excerpt.replace(/<br>/gim, '').trim() === '') {
|
||||
excerpt = ''
|
||||
}
|
||||
|
||||
return excerpt
|
||||
},
|
||||
isAuthor() {
|
||||
return this.$store.getters['auth/user'].id === this.post.author.id
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
6
cypress.env.template.json
Normal file
6
cypress.env.template.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"SEED_SERVER_HOST": "http://localhost:4001",
|
||||
"NEO4J_URI": "bolt://localhost:7687",
|
||||
"NEO4J_USERNAME": "neo4j",
|
||||
"NEO4J_PASSWORD": "letmein"
|
||||
}
|
||||
@ -4,11 +4,7 @@ Feature: Authentication
|
||||
In order to attribute posts and other contributions to their authors
|
||||
|
||||
Background:
|
||||
Given my account has the following details:
|
||||
| name | email | password | type
|
||||
| Peter Lustig | admin@example.org | 1234 | Admin
|
||||
| Bob der Bausmeister | moderator@example.org | 1234 | Moderator
|
||||
| Jenny Rostock" | user@example.org | 1234 | User
|
||||
Given I have a user account
|
||||
|
||||
Scenario: Log in
|
||||
When I visit the "/login" page
|
||||
|
||||
@ -14,28 +14,27 @@ Feature: Tags and Categories
|
||||
looking at the popularity of a tag.
|
||||
|
||||
Background:
|
||||
Given we have a selection of tags and categories as well as posts
|
||||
And my user account has the role "administrator"
|
||||
Given I am logged in
|
||||
Given my user account has the role "admin"
|
||||
And we have a selection of tags and categories as well as posts
|
||||
And I am logged in
|
||||
|
||||
Scenario: See an overview of categories
|
||||
When I navigate to the administration dashboard
|
||||
And I click on "Categories"
|
||||
Then I can see a list of categories ordered by post count:
|
||||
| Icon | Name | Post Count |
|
||||
| | Just For Fun | 5 |
|
||||
| | Happyness & Values | 2 |
|
||||
| | Health & Wellbeing | 1 |
|
||||
| Icon | Name | Posts |
|
||||
| | Just For Fun | 2 |
|
||||
| | Happyness & Values | 1 |
|
||||
| | Health & Wellbeing | 0 |
|
||||
|
||||
Scenario: See an overview of tags
|
||||
When I navigate to the administration dashboard
|
||||
And I click on "Tags"
|
||||
Then I can see a list of tags ordered by user and post count:
|
||||
| # | Name | Nutzer | Beiträge |
|
||||
| 1 | Naturschutz | 2 | 2 |
|
||||
| 2 | Freiheit | 2 | 2 |
|
||||
| 3 | Umwelt | 1 | 1 |
|
||||
| 4 | Demokratie | 1 | 1 |
|
||||
Then I can see a list of tags ordered by user count:
|
||||
| # | Name | Users | Posts |
|
||||
| 1 | Democracy | 2 | 3 |
|
||||
| 2 | Ecology | 1 | 1 |
|
||||
| 3 | Nature | 1 | 2 |
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,21 +7,18 @@ Feature: About me and location
|
||||
to search for users by location.
|
||||
|
||||
Background:
|
||||
Given I am logged in
|
||||
Given I have a user account
|
||||
And I am logged in
|
||||
And I am on the "settings" page
|
||||
|
||||
Scenario: Change username
|
||||
When I save "Hansi" as my new name
|
||||
Then I can see my new name "Hansi" when I click on my profile picture in the top right
|
||||
|
||||
Scenario: Keep changes after refresh
|
||||
When I changed my username to "Hansi" previously
|
||||
And I refresh the page
|
||||
Then my new username is still there
|
||||
And when I refresh the page
|
||||
Then the name "Hansi" is still there
|
||||
|
||||
Scenario Outline: I set my location to "<location>"
|
||||
When I save "<location>" as my location
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the location in the info box below my avatar
|
||||
|
||||
@ -36,10 +33,5 @@ Feature: About me and location
|
||||
"""
|
||||
Ich lebe fettlos, fleischlos, fischlos dahin, fühle mich aber ganz wohl dabei
|
||||
"""
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the text in the info box below my avatar
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,13 +9,13 @@ Feature: Report and Moderate
|
||||
|
||||
Background:
|
||||
Given we have the following posts in our database:
|
||||
| Author | Title | Content | Slug |
|
||||
| David Irving | The Truth about the Holocaust | It never existed! | the-truth-about-the-holocaust |
|
||||
| Author | id | title | content |
|
||||
| David Irving | p1 | The Truth about the Holocaust | It never existed! |
|
||||
|
||||
Scenario Outline: Report a post from various pages
|
||||
Given I am logged in with a "user" role
|
||||
And I see David Irving's post on the <Page>
|
||||
When I click on "Report Contribution" from the triple dot menu of the post
|
||||
When I see David Irving's post on the <Page>
|
||||
And I click on "Report Contribution" from the triple dot menu of the post
|
||||
And I confirm the reporting dialog because it is a criminal act under German law:
|
||||
"""
|
||||
Do you really want to report the contribution "The Truth about the Holocaust"?
|
||||
@ -45,8 +45,8 @@ Feature: Report and Moderate
|
||||
|
||||
Scenario: Review reported content
|
||||
Given somebody reported the following posts:
|
||||
| Slug |
|
||||
| the-truth-about-the-holocaust |
|
||||
| id |
|
||||
| p1 |
|
||||
And I am logged in with a "moderator" role
|
||||
When I click on the avatar menu in the top right corner
|
||||
And I click on "Moderation"
|
||||
|
||||
25
cypress/integration/06.WritePost.feature
Normal file
25
cypress/integration/06.WritePost.feature
Normal file
@ -0,0 +1,25 @@
|
||||
Feature: Create a post
|
||||
As a user
|
||||
I would like to create a post
|
||||
To say something to everyone in the community
|
||||
|
||||
Background:
|
||||
Given I have a user account
|
||||
And I am logged in
|
||||
And I am on the "landing" page
|
||||
|
||||
Scenario: Create a post
|
||||
When I click on the big plus icon in the bottom right corner to create post
|
||||
And I choose "My first post" as the title of the post
|
||||
And I type in the following text:
|
||||
"""
|
||||
Human Connection is a free and open-source social network
|
||||
for active citizenship.
|
||||
"""
|
||||
And I click on "Save"
|
||||
Then I get redirected to "/post/my-first-post/"
|
||||
And the post was saved successfully
|
||||
|
||||
Scenario: See a post on the landing page
|
||||
Given I previously created a post
|
||||
Then the post shows up on the landing page at position 1
|
||||
@ -2,18 +2,6 @@ import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
/* global cy */
|
||||
|
||||
const lastColumnIsSortedInDescendingOrder = () => {
|
||||
cy.get('tbody')
|
||||
.find('tr td:last-child')
|
||||
.then(lastColumn => {
|
||||
cy.wrap(lastColumn)
|
||||
const values = lastColumn
|
||||
.map((i, td) => parseInt(td.textContent))
|
||||
.toArray()
|
||||
const orderedDescending = values.slice(0).sort((a, b) => b - a)
|
||||
return cy.wrap(values).should('deep.eq', orderedDescending)
|
||||
})
|
||||
}
|
||||
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
@ -23,17 +11,27 @@ When('I navigate to the administration dashboard', () => {
|
||||
})
|
||||
|
||||
Then('I can see a list of categories ordered by post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 3)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
table.hashes().forEach(({Name, Posts}, index) => {
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(2)`)
|
||||
.should('contain', Name)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(3)`)
|
||||
.should('contain', Posts)
|
||||
})
|
||||
})
|
||||
|
||||
Then('I can see a list of tags ordered by user and post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
Then('I can see a list of tags ordered by user count:', table => {
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 4)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
table.hashes().forEach(({Name, Users, Posts}, index) => {
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(2)`)
|
||||
.should('contain', Name)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(3)`)
|
||||
.should('contain', Users)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(4)`)
|
||||
.should('contain', Posts)
|
||||
})
|
||||
})
|
||||
|
||||
@ -3,9 +3,9 @@ import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
/* global cy */
|
||||
|
||||
let lastReportTitle
|
||||
let dummyReportedPostTitle = 'Hacker, Freaks und Funktionäre'
|
||||
let dummyReportedPostSlug = 'hacker-freaks-und-funktionareder-ccc'
|
||||
let dummyAuthorName = 'Jenny Rostock'
|
||||
let davidIrvingPostTitle = 'The Truth about the Holocaust'
|
||||
let davidIrvingPostSlug = 'the-truth-about-the-holocaust'
|
||||
let davidIrvingName = 'David Irving'
|
||||
|
||||
const savePostTitle = $post => {
|
||||
return $post
|
||||
@ -23,21 +23,27 @@ Given("I see David Irving's post on the landing page", page => {
|
||||
})
|
||||
|
||||
Given("I see David Irving's post on the post page", page => {
|
||||
cy.visit(`/post/${dummyReportedPostSlug}`)
|
||||
cy.contains(dummyReportedPostTitle) // wait
|
||||
cy.visit(`/post/${davidIrvingPostSlug}`)
|
||||
cy.contains(davidIrvingPostTitle) // wait
|
||||
})
|
||||
|
||||
Given('I am logged in with a {string} role', role => {
|
||||
cy.loginAs(role)
|
||||
cy.factory().create('User', {
|
||||
email: `${role}@example.org`,
|
||||
password: '1234',
|
||||
role
|
||||
})
|
||||
cy.login({
|
||||
email: `${role}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
})
|
||||
|
||||
When(
|
||||
'I click on "Report Contribution" from the triple dot menu of the post',
|
||||
() => {
|
||||
//TODO: match the created post title, not a dummy post title
|
||||
cy.contains('.ds-card', dummyReportedPostTitle)
|
||||
cy.contains('.ds-card', davidIrvingPostTitle)
|
||||
.find('.content-menu-trigger')
|
||||
.first()
|
||||
.click()
|
||||
|
||||
cy.get('.popover .ds-menu-item-link')
|
||||
@ -49,8 +55,7 @@ When(
|
||||
When(
|
||||
'I click on "Report User" from the triple dot menu in the user info box',
|
||||
() => {
|
||||
//TODO: match the created post author, not a dummy author
|
||||
cy.contains('.ds-card', dummyAuthorName)
|
||||
cy.contains('.ds-card', davidIrvingName)
|
||||
.find('.content-menu-trigger')
|
||||
.first()
|
||||
.click()
|
||||
@ -106,12 +111,8 @@ Then(`I can't see the moderation menu item`, () => {
|
||||
.should('not.exist')
|
||||
})
|
||||
|
||||
When(/^I confirm the reporting dialog .*:$/, () => {
|
||||
//TODO: take message from method argument
|
||||
//TODO: match the right post
|
||||
const message = 'Do you really want to report the'
|
||||
When(/^I confirm the reporting dialog .*:$/, (message) => {
|
||||
cy.contains(message) // wait for element to become visible
|
||||
//TODO: cy.get('.ds-modal').contains(dummyReportedPostTitle)
|
||||
cy.get('.ds-modal').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send Report')
|
||||
@ -120,22 +121,28 @@ When(/^I confirm the reporting dialog .*:$/, () => {
|
||||
})
|
||||
|
||||
Given('somebody reported the following posts:', table => {
|
||||
table.hashes().forEach(row => {
|
||||
//TODO: calll factory here
|
||||
// const options = Object.assign({}, row, { reported: true })
|
||||
//create('post', options)
|
||||
table.hashes().forEach(({ id }) => {
|
||||
const reporter = {
|
||||
email: `reporter${id}@example.org`,
|
||||
password: '1234'
|
||||
}
|
||||
cy.factory()
|
||||
.create('User', reporter)
|
||||
.authenticateAs(reporter)
|
||||
.create('Report', {
|
||||
description: "I don't like this post",
|
||||
resource: { id, type: 'contribution' }
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Then('I see all the reported posts including the one from above', () => {
|
||||
//TODO: match the right post
|
||||
cy.get('table tbody').within(() => {
|
||||
cy.contains('tr', dummyReportedPostTitle)
|
||||
cy.contains('tr', davidIrvingPostTitle)
|
||||
})
|
||||
})
|
||||
|
||||
Then('each list item links to the post page', () => {
|
||||
//TODO: match the right post
|
||||
cy.contains(dummyReportedPostTitle).click()
|
||||
cy.contains(davidIrvingPostTitle).click()
|
||||
cy.location('pathname').should('contain', '/post')
|
||||
})
|
||||
|
||||
@ -4,7 +4,6 @@ import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
let aboutMeText
|
||||
let myLocation
|
||||
let myName
|
||||
|
||||
const matchNameInUserMenu = name => {
|
||||
cy.get('.avatar-menu').click() // open
|
||||
@ -12,18 +11,13 @@ const matchNameInUserMenu = name => {
|
||||
cy.get('.avatar-menu').click() // close again
|
||||
}
|
||||
|
||||
const setUserName = name => {
|
||||
When('I save {string} as my new name', name => {
|
||||
cy.get('input[id=name]')
|
||||
.clear()
|
||||
.type(name)
|
||||
cy.get('[type=submit]')
|
||||
.click()
|
||||
.not('[disabled]')
|
||||
myName = name
|
||||
}
|
||||
|
||||
When('I save {string} as my new name', name => {
|
||||
setUserName(name)
|
||||
})
|
||||
|
||||
When('I save {string} as my location', location => {
|
||||
@ -47,31 +41,20 @@ When('I have the following self-description:', text => {
|
||||
aboutMeText = text
|
||||
})
|
||||
|
||||
When('my username is {string}', name => {
|
||||
if (myName !== name) {
|
||||
setUserName(name)
|
||||
}
|
||||
matchNameInUserMenu(name)
|
||||
})
|
||||
|
||||
When('people visit my profile page', url => {
|
||||
cy.visitMyProfile()
|
||||
cy.openPage('/profile/peter-pan')
|
||||
})
|
||||
|
||||
When('they can see the text in the info box below my avatar', () => {
|
||||
cy.contains(aboutMeText)
|
||||
})
|
||||
|
||||
When('I changed my username to {string} previously', name => {
|
||||
myName = name
|
||||
})
|
||||
|
||||
Then('they can see the location in the info box below my avatar', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
cy.contains(myLocation)
|
||||
})
|
||||
|
||||
Then('my new username is still there', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
Then('the name {string} is still there', name => {
|
||||
matchNameInUserMenu(name)
|
||||
})
|
||||
|
||||
Then(
|
||||
|
||||
@ -1,26 +1,87 @@
|
||||
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
import { getLangByName } from '../../support/helpers'
|
||||
import users from '../../fixtures/users.json'
|
||||
|
||||
/* global cy */
|
||||
|
||||
let lastPost = {}
|
||||
|
||||
const loginCredentials = {
|
||||
email: 'peterpan@example.org',
|
||||
password: '1234'
|
||||
}
|
||||
const narratorParams = {
|
||||
name: 'Peter Pan',
|
||||
...loginCredentials
|
||||
}
|
||||
|
||||
Given('I am logged in', () => {
|
||||
cy.loginAs('admin')
|
||||
})
|
||||
Given('I am logged in as {string}', userType => {
|
||||
cy.loginAs(userType)
|
||||
cy.login(loginCredentials)
|
||||
})
|
||||
|
||||
Given('we have a selection of tags and categories as well as posts', () => {
|
||||
// TODO: use db factories instead of seed data
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Category', {
|
||||
id: 'cat1',
|
||||
name: 'Just For Fun',
|
||||
slug: 'justforfun',
|
||||
icon: 'smile'
|
||||
})
|
||||
.create('Category', {
|
||||
id: 'cat2',
|
||||
name: 'Happyness & Values',
|
||||
slug: 'happyness-values',
|
||||
icon: 'heart-o'
|
||||
})
|
||||
.create('Category', {
|
||||
id: 'cat3',
|
||||
name: 'Health & Wellbeing',
|
||||
slug: 'health-wellbeing',
|
||||
icon: 'medkit'
|
||||
})
|
||||
.create('Tag', { id: 't1', name: 'Ecology' })
|
||||
.create('Tag', { id: 't2', name: 'Nature' })
|
||||
.create('Tag', { id: 't3', name: 'Democracy' })
|
||||
|
||||
const someAuthor = {
|
||||
id: 'authorId',
|
||||
email: 'author@example.org',
|
||||
password: '1234'
|
||||
}
|
||||
cy.factory()
|
||||
.create('User', someAuthor)
|
||||
.authenticateAs(someAuthor)
|
||||
.create('Post', { id: 'p0' })
|
||||
.create('Post', { id: 'p1' })
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Post', { id: 'p2' })
|
||||
.relate('Post', 'Categories', { from: 'p0', to: 'cat1' })
|
||||
.relate('Post', 'Categories', { from: 'p1', to: 'cat2' })
|
||||
.relate('Post', 'Categories', { from: 'p2', to: 'cat1' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't1' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't2' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't3' })
|
||||
.relate('Post', 'Tags', { from: 'p1', to: 't2' })
|
||||
.relate('Post', 'Tags', { from: 'p1', to: 't3' })
|
||||
.relate('Post', 'Tags', { from: 'p2', to: 't3' })
|
||||
})
|
||||
|
||||
Given('my account has the following details:', table => {
|
||||
// TODO: use db factories instead of seed data
|
||||
Given('we have the following user accounts:', table => {
|
||||
table.hashes().forEach(params => {
|
||||
cy.factory().create('User', params)
|
||||
})
|
||||
})
|
||||
|
||||
Given('I have a user account', () => {
|
||||
cy.factory().create('User', narratorParams)
|
||||
})
|
||||
|
||||
Given('my user account has the role {string}', role => {
|
||||
// TODO: use db factories instead of seed data
|
||||
cy.factory().create('User', {
|
||||
role,
|
||||
...loginCredentials
|
||||
})
|
||||
})
|
||||
|
||||
When('I log out', cy.logout)
|
||||
@ -34,10 +95,10 @@ Given('I am on the {string} page', page => {
|
||||
})
|
||||
|
||||
When('I fill in my email and password combination and click submit', () => {
|
||||
cy.login('admin@example.org', 1234)
|
||||
cy.login(loginCredentials)
|
||||
})
|
||||
|
||||
When('I refresh the page', () => {
|
||||
When(/(?:when )?I refresh the page/, () => {
|
||||
cy.reload()
|
||||
})
|
||||
|
||||
@ -49,7 +110,7 @@ When('I log out through the menu in the top right corner', () => {
|
||||
})
|
||||
|
||||
Then('I can see my name {string} in the dropdown menu', () => {
|
||||
cy.get('.avatar-menu-popover').should('contain', users.admin.name)
|
||||
cy.get('.avatar-menu-popover').should('contain', narratorParams.name)
|
||||
})
|
||||
|
||||
Then('I see the login screen again', () => {
|
||||
@ -63,7 +124,7 @@ Then('I can click on my profile picture in the top right corner', () => {
|
||||
|
||||
Then('I am still logged in', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover').contains(users.admin.name)
|
||||
cy.get('.avatar-menu-popover').contains(narratorParams.name)
|
||||
})
|
||||
|
||||
When('I select {string} in the language menu', name => {
|
||||
@ -90,9 +151,18 @@ When('I press {string}', label => {
|
||||
})
|
||||
|
||||
Given('we have the following posts in our database:', table => {
|
||||
table.hashes().forEach(row => {
|
||||
//TODO: calll factory here
|
||||
//create('post', row)
|
||||
table.hashes().forEach(({ Author, id, title, content }) => {
|
||||
cy.factory()
|
||||
.create('User', {
|
||||
name: Author,
|
||||
email: `${Author}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
.authenticateAs({
|
||||
email: `${Author}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
.create('Post', { id, title, content })
|
||||
})
|
||||
})
|
||||
|
||||
@ -103,3 +173,42 @@ Then('I see a success message:', message => {
|
||||
When('I click on the avatar menu in the top right corner', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
})
|
||||
|
||||
When(
|
||||
'I click on the big plus icon in the bottom right corner to create post',
|
||||
() => {
|
||||
cy.get('.post-add-button').click()
|
||||
}
|
||||
)
|
||||
|
||||
Given('I previously created a post', () => {
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Post', lastPost)
|
||||
})
|
||||
|
||||
When('I choose {string} as the title of the post', title => {
|
||||
lastPost.title = title.replace('\n', ' ')
|
||||
cy.get('input[name="title"]').type(lastPost.title)
|
||||
})
|
||||
|
||||
When('I type in the following text:', text => {
|
||||
lastPost.content = text.replace('\n', ' ')
|
||||
cy.get('.ProseMirror').type(lastPost.content)
|
||||
})
|
||||
|
||||
Then('the post shows up on the landing page at position {int}', index => {
|
||||
cy.openPage('landing')
|
||||
const selector = `:nth-child(${index}) > .ds-card > .ds-card-content`
|
||||
cy.get(selector).should('contain', lastPost.title)
|
||||
cy.get(selector).should('contain', lastPost.content)
|
||||
})
|
||||
|
||||
Then('I get redirected to {string}', route => {
|
||||
cy.location('pathname').should('contain', route)
|
||||
})
|
||||
|
||||
Then('the post was saved successfully', () => {
|
||||
cy.get('.ds-card-header > .ds-heading').should('contain', lastPost.title)
|
||||
cy.get('.content').should('contain', lastPost.content)
|
||||
})
|
||||
|
||||
@ -35,14 +35,7 @@ Cypress.Commands.add('switchLanguage', (name, force) => {
|
||||
}
|
||||
})
|
||||
|
||||
Cypress.Commands.add('visitMyProfile', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.find('a[href^="/profile/"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
Cypress.Commands.add('login', (email, password) => {
|
||||
Cypress.Commands.add('login', ({ email, password }) => {
|
||||
cy.visit(`/login`)
|
||||
cy.get('input[name=email]')
|
||||
.trigger('focus')
|
||||
@ -56,11 +49,6 @@ Cypress.Commands.add('login', (email, password) => {
|
||||
cy.location('pathname').should('eq', '/') // we're in!
|
||||
})
|
||||
|
||||
Cypress.Commands.add('loginAs', role => {
|
||||
role = role || 'admin'
|
||||
cy.login(users[role].email, users[role].password)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('logout', (email, password) => {
|
||||
cy.visit(`/logout`)
|
||||
cy.location('pathname').should('contain', '/login') // we're out
|
||||
|
||||
43
cypress/support/factories.js
Normal file
43
cypress/support/factories.js
Normal file
@ -0,0 +1,43 @@
|
||||
// TODO: find a better way how to import the factories
|
||||
import Factory from '../../../Nitro-Backend/src/seed/factories'
|
||||
import { getDriver } from '../../../Nitro-Backend/src/bootstrap/neo4j'
|
||||
|
||||
const neo4jDriver = getDriver({
|
||||
uri: Cypress.env('NEO4J_URI'),
|
||||
username: Cypress.env('NEO4J_USERNAME'),
|
||||
password: Cypress.env('NEO4J_PASSWORD')
|
||||
})
|
||||
const factory = Factory({ neo4jDriver })
|
||||
const seedServerHost = Cypress.env('SEED_SERVER_HOST')
|
||||
|
||||
beforeEach(async () => {
|
||||
await factory.cleanDatabase({ seedServerHost, neo4jDriver })
|
||||
})
|
||||
|
||||
Cypress.Commands.add('factory', () => {
|
||||
return Factory({seedServerHost})
|
||||
})
|
||||
|
||||
Cypress.Commands.add(
|
||||
'create',
|
||||
{ prevSubject: true },
|
||||
(factory, node, properties) => {
|
||||
return factory.create(node, properties)
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'relate',
|
||||
{ prevSubject: true },
|
||||
(factory, node, relationship, properties) => {
|
||||
return factory.relate(node, relationship, properties)
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'authenticateAs',
|
||||
{ prevSubject: true },
|
||||
(factory, loginCredentials) => {
|
||||
return factory.authenticateAs(loginCredentials)
|
||||
}
|
||||
)
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
import './factories'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
@ -8,9 +8,9 @@ services:
|
||||
volumes:
|
||||
- .:/nitro-web
|
||||
- node_modules:/nitro-web/node_modules
|
||||
- node_modules_styleguide:/nitro-web/styleguide/node_modules
|
||||
- nuxt:/nitro-web/.nuxt
|
||||
command: yarn run dev
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
node_modules_styleguide:
|
||||
nuxt:
|
||||
|
||||
@ -5,3 +5,5 @@ services:
|
||||
build:
|
||||
context: .
|
||||
target: build-and-test
|
||||
environment:
|
||||
- BACKEND_URL=http://backend:4123
|
||||
|
||||
28
graphql/PostMutations.js
Normal file
28
graphql/PostMutations.js
Normal file
@ -0,0 +1,28 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default app => {
|
||||
return {
|
||||
CreatePost: gql(`
|
||||
mutation($title: String!, $content: String!) {
|
||||
CreatePost(title: $title, content: $content) {
|
||||
id
|
||||
title
|
||||
slug
|
||||
content
|
||||
contentExcerpt
|
||||
}
|
||||
}
|
||||
`),
|
||||
UpdatePost: gql(`
|
||||
mutation($id: ID!, $title: String!, $content: String!) {
|
||||
UpdatePost(id: $id, title: $title, content: $content) {
|
||||
id
|
||||
title
|
||||
slug
|
||||
content
|
||||
contentExcerpt
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,8 @@
|
||||
"create": "Erstellen",
|
||||
"save": "Speichern",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen"
|
||||
"delete": "Löschen",
|
||||
"cancel": "Abbrechen"
|
||||
},
|
||||
"login": {
|
||||
"copy": "Wenn Du bereits ein Konto bei Human Connection hast, melde Dich bitte hier an.",
|
||||
@ -105,6 +106,14 @@
|
||||
"reporter": "gemeldet von"
|
||||
}
|
||||
},
|
||||
"contribution": {
|
||||
"edit": "Beitrag bearbeiten",
|
||||
"delete": "Beitrag löschen"
|
||||
},
|
||||
"comment": {
|
||||
"edit": "Kommentar bearbeiten",
|
||||
"delete": "Kommentar löschen"
|
||||
},
|
||||
"disable": {
|
||||
"user": {
|
||||
"title": "Nutzer sperren",
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
"create": "Create",
|
||||
"save": "Save",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete"
|
||||
"delete": "Delete",
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"login": {
|
||||
"copy": "If you already have a human-connection account, login here.",
|
||||
@ -105,6 +106,14 @@
|
||||
"reporter": "reported by"
|
||||
}
|
||||
},
|
||||
"contribution": {
|
||||
"edit": "Edit Contribution",
|
||||
"delete": "Delete Contribution"
|
||||
},
|
||||
"comment": {
|
||||
"edit": "Edit Comment",
|
||||
"delete": "Delete Comment"
|
||||
},
|
||||
"disable": {
|
||||
"user": {
|
||||
"title": "Disable User",
|
||||
|
||||
@ -9,6 +9,8 @@ module.exports = {
|
||||
dev: dev,
|
||||
debug: dev ? 'nuxt:*,app' : null,
|
||||
|
||||
modern: 'server',
|
||||
|
||||
transition: {
|
||||
name: 'slide-up',
|
||||
mode: 'out-in'
|
||||
@ -41,7 +43,14 @@ module.exports = {
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: pkg.description }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
|
||||
script: [
|
||||
{
|
||||
src:
|
||||
'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver',
|
||||
body: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
/*
|
||||
@ -61,10 +70,10 @@ module.exports = {
|
||||
** Plugins to load before mounting the App
|
||||
*/
|
||||
plugins: [
|
||||
{ src: '~/plugins/styleguide.js', ssr: true },
|
||||
{ src: '~/plugins/i18n.js', ssr: true },
|
||||
{ src: '~/plugins/axios.js', ssr: false },
|
||||
{ src: '~/plugins/keep-alive.js', ssr: false },
|
||||
{ src: '~/plugins/design-system.js', ssr: true },
|
||||
{ src: '~/plugins/vue-directives.js', ssr: false },
|
||||
{ src: '~/plugins/v-tooltip.js', ssr: false },
|
||||
{ src: '~/plugins/izi-toast.js', ssr: false },
|
||||
@ -89,13 +98,14 @@ module.exports = {
|
||||
'cookie-universal-nuxt',
|
||||
'@nuxtjs/apollo',
|
||||
'@nuxtjs/axios',
|
||||
'portal-vue/nuxt',
|
||||
[
|
||||
'nuxt-sass-resources-loader',
|
||||
path.resolve(__dirname, './styleguide/src/system/styles/shared.scss')
|
||||
]
|
||||
'@nuxtjs/style-resources',
|
||||
'portal-vue/nuxt'
|
||||
],
|
||||
|
||||
styleResources: {
|
||||
scss: ['@human-connection/styleguide/dist/shared.scss']
|
||||
},
|
||||
|
||||
/*
|
||||
** Axios module configuration
|
||||
*/
|
||||
@ -157,12 +167,6 @@ module.exports = {
|
||||
** Build configuration
|
||||
*/
|
||||
build: {
|
||||
/*
|
||||
* TODO: import the polyfill instead of using the deprecated vendor key
|
||||
* Polyfill missing ES6 & 7 Methods to work on older Browser
|
||||
*/
|
||||
vendor: ['@babel/polyfill'],
|
||||
|
||||
/*
|
||||
** You can extend webpack config here
|
||||
*/
|
||||
@ -176,14 +180,6 @@ module.exports = {
|
||||
exclude: /(node_modules)/
|
||||
})
|
||||
}
|
||||
config.resolve.alias['@@'] = path.resolve(
|
||||
__dirname,
|
||||
'./styleguide/src/system'
|
||||
)
|
||||
config.module.rules.push({
|
||||
resourceQuery: /blockType=docs/,
|
||||
loader: require.resolve('./styleguide/src/loader/docs-trim-loader.js')
|
||||
})
|
||||
const svgRule = config.module.rules.find(rule => rule.test.test('.svg'))
|
||||
svgRule.test = /\.(png|jpe?g|gif|webp)$/
|
||||
config.module.rules.push({
|
||||
|
||||
94
package.json
94
package.json
@ -10,8 +10,8 @@
|
||||
"start": "cross-env node server/index.js",
|
||||
"generate": "nuxt generate",
|
||||
"lint": "eslint --ext .js,.vue .",
|
||||
"styleguide": "cd ./styleguide && yarn dev",
|
||||
"styleguide:build": "cd ./styleguide && yarn build:lib && cd ../",
|
||||
"styleguide": "echo 'Command styleguide is Deprecated!'",
|
||||
"styleguide:build": "echo 'Command styleguide:build is Deprecated!'",
|
||||
"test": "jest",
|
||||
"precommit": "yarn lint",
|
||||
"e2e:local": "cypress run --headed",
|
||||
@ -32,55 +32,59 @@
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"^@/(.*)$": "<rootDir>/src/$1",
|
||||
"^@@/(.*)$": "<rootDir>/styleguide/src/system/$1",
|
||||
"^~/(.*)$": "<rootDir>/$1"
|
||||
},
|
||||
"modulePathIgnorePatterns": [
|
||||
"<rootDir>/styleguide"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/apollo": "^4.0.0-rc3",
|
||||
"@nuxtjs/axios": "^5.3.6",
|
||||
"@nuxtjs/dotenv": "^1.3.0",
|
||||
"accounting": "^0.4.1",
|
||||
"cookie-universal-nuxt": "^2.0.14",
|
||||
"cross-env": "^5.2.0",
|
||||
"date-fns": "^2.0.0-alpha.26",
|
||||
"express": "^4.16.3",
|
||||
"global": "^4.3.2",
|
||||
"graphql": "^14.1.1",
|
||||
"graphql-tag": "^2.10.1",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"nuxt": "^2.0.0",
|
||||
"nuxt-env": "^0.0.4",
|
||||
"nuxt-sass-resources-loader": "^2.0.5",
|
||||
"@nuxtjs/apollo": "4.0.0-rc4",
|
||||
"@nuxtjs/axios": "~5.3.6",
|
||||
"@nuxtjs/dotenv": "~1.3.0",
|
||||
"@nuxtjs/style-resources": "~0.1.2",
|
||||
"accounting": "~0.4.1",
|
||||
"apollo-cache-inmemory": "~1.5.0",
|
||||
"apollo-client": "~2.5.1",
|
||||
"cookie-universal-nuxt": "~2.0.14",
|
||||
"cross-env": "~5.2.0",
|
||||
"date-fns": "2.0.0-alpha.27",
|
||||
"express": "~4.16.4",
|
||||
"graphql": "~14.1.1",
|
||||
"jsonwebtoken": "~8.5.0",
|
||||
"linkify-it": "~2.1.0",
|
||||
"nuxt": "~2.4.5",
|
||||
"nuxt-env": "~0.1.0",
|
||||
"portal-vue": "~1.5.1",
|
||||
"v-tooltip": "^2.0.0-rc.33",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"@human-connection/styleguide": "~0.5.0",
|
||||
"v-tooltip": "~2.0.0-rc.33",
|
||||
"vue-count-to": "~1.0.13",
|
||||
"string-hash": "^1.1.3",
|
||||
"tiptap": "^1.13.0",
|
||||
"tiptap-extensions": "^1.13.0",
|
||||
"vue-izitoast": "1.1.2",
|
||||
"vue-sweetalert-icons": "^3.2.0",
|
||||
"vuex-i18n": "^1.11.0"
|
||||
"vue-sweetalert-icons": "~3.2.0",
|
||||
"vuex-i18n": "~1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/eslint-config-prettier": "^4.0.1",
|
||||
"@vue/server-test-utils": "^1.0.0-beta.29",
|
||||
"@vue/test-utils": "^1.0.0-beta.28",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^23.6.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"cypress-cucumber-preprocessor": "^1.9.1",
|
||||
"eslint": "^5.13.0",
|
||||
"eslint-config-prettier": "^3.1.0",
|
||||
"eslint-loader": "^2.0.0",
|
||||
"eslint-plugin-prettier": "3.0.1",
|
||||
"eslint-plugin-vue": "^5.1.0",
|
||||
"jest": "^23.6.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"nodemon": "^1.18.9",
|
||||
"prettier": "1.14.3",
|
||||
"sass-loader": "^7.1.0",
|
||||
"vue-jest": "^3.0.2",
|
||||
"vue-svg-loader": "^0.11.0"
|
||||
"@babel/core": "~7.3.4",
|
||||
"@babel/preset-env": "~7.3.1",
|
||||
"@vue/cli-shared-utils": "~3.4.0",
|
||||
"@vue/eslint-config-prettier": "~4.0.1",
|
||||
"@vue/server-test-utils": "~1.0.0-beta.29",
|
||||
"@vue/test-utils": "~1.0.0-beta.29",
|
||||
"babel-core": "~7.0.0-bridge.0",
|
||||
"babel-eslint": "~10.0.1",
|
||||
"babel-jest": "~24.1.0",
|
||||
"cypress-cucumber-preprocessor": "~1.11.0",
|
||||
"eslint": "~5.14.1",
|
||||
"eslint-config-prettier": "~3.6.0",
|
||||
"eslint-loader": "~2.1.2",
|
||||
"eslint-plugin-prettier": "~3.0.1",
|
||||
"eslint-plugin-vue": "~5.2.2",
|
||||
"jest": "~24.1.0",
|
||||
"node-sass": "~4.11.0",
|
||||
"nodemon": "~1.18.10",
|
||||
"prettier": "~1.14.3",
|
||||
"sass-loader": "~7.1.0",
|
||||
"vue-jest": "~3.0.3",
|
||||
"vue-svg-loader": "~0.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('admin.notifications.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('admin.organizations.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('admin.pages.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('admin.settings.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('admin.users.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -13,6 +13,16 @@
|
||||
<hc-post-card :post="post" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<no-ssr>
|
||||
<ds-button
|
||||
v-tooltip="{content: 'Create a new Post', placement: 'left', delay: { show: 500 }}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="post-add-button"
|
||||
icon="plus"
|
||||
size="x-large"
|
||||
primary
|
||||
/>
|
||||
</no-ssr>
|
||||
<hc-load-more
|
||||
v-if="true"
|
||||
:loading="$apollo.loading"
|
||||
@ -82,7 +92,7 @@ export default {
|
||||
query() {
|
||||
return gql(`
|
||||
query Post($first: Int, $offset: Int) {
|
||||
Post(first: $first, offset: $offset) {
|
||||
Post(first: $first, offset: $offset, orderBy: createdAt_desc) {
|
||||
id
|
||||
title
|
||||
contentExcerpt
|
||||
@ -123,8 +133,20 @@ export default {
|
||||
first: this.pageSize,
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.post-add-button {
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
top: 100vh;
|
||||
left: 100vw;
|
||||
transform: translate(-120%, -120%);
|
||||
box-shadow: $box-shadow-x-large;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -113,16 +113,16 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
asyncData({ store, redirect }) {
|
||||
if (store.getters['auth/isLoggedIn']) {
|
||||
redirect('/')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pending() {
|
||||
return this.$store.getters['auth/pending']
|
||||
}
|
||||
},
|
||||
asyncData({ store, redirect }) {
|
||||
if (store.getters['auth/isLoggedIn']) {
|
||||
redirect('/')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
// NOTE: quick fix for jumping flexbox implementation
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
context="contribution"
|
||||
:item-id="post.id"
|
||||
:name="post.title"
|
||||
:is-owner="isAuthor(post.author.id)"
|
||||
/>
|
||||
</no-ssr>
|
||||
<ds-space margin-bottom="small" />
|
||||
@ -97,6 +98,7 @@
|
||||
style="float-right"
|
||||
:item-id="comment.id"
|
||||
:name="comment.author.name"
|
||||
:is-owner="isAuthor(comment.author.id)"
|
||||
/>
|
||||
</no-ssr>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
@ -160,6 +162,11 @@ export default {
|
||||
this.title = this.post.title
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isAuthor(id) {
|
||||
return this.$store.getters['auth/user'].id === id
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query() {
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
<ds-flex-item
|
||||
v-for="relatedPost in post.relatedContributions"
|
||||
:key="relatedPost.id"
|
||||
:width="{ base: '50%' }"
|
||||
:width="{ base: '100%', lg: 1 }"
|
||||
>
|
||||
<hc-post-card :post="relatedPost" />
|
||||
</ds-flex-item>
|
||||
@ -70,7 +70,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
post() {
|
||||
return this.Post ? this.Post[0] : {}
|
||||
return this.Post ? this.Post[0] || {} : {}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card header="Werde aktiv!">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
24
pages/post/create.vue
Normal file
24
pages/post/create.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<ds-flex
|
||||
:width="{ base: '100%' }"
|
||||
gutter="base"
|
||||
>
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<hc-contribution-form />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }">
|
||||
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcContributionForm from '~/components/ContributionForm.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm
|
||||
}
|
||||
}
|
||||
</script>
|
||||
77
pages/post/edit/_id.vue
Normal file
77
pages/post/edit/_id.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<ds-flex
|
||||
:width="{ base: '100%' }"
|
||||
gutter="base"
|
||||
>
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<hc-contribution-form :contribution="contribution" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }">
|
||||
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcContributionForm from '~/components/ContributionForm.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters['auth/user']
|
||||
},
|
||||
author() {
|
||||
return this.contribution ? this.contribution.author : {}
|
||||
},
|
||||
contribution() {
|
||||
return this.Post ? this.Post[0] : {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
contribution() {
|
||||
if (this.author.id !== this.user.id) {
|
||||
throw new Error(`You can't edit that!`)
|
||||
}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query() {
|
||||
return gql(`
|
||||
query($id: ID!) {
|
||||
Post(id: $id) {
|
||||
id
|
||||
title
|
||||
content
|
||||
createdAt
|
||||
slug
|
||||
image
|
||||
author {
|
||||
id
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
id: this.$route.params.id || 'p1'
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -23,6 +23,7 @@
|
||||
context="user"
|
||||
:item-id="user.id"
|
||||
:name="user.name"
|
||||
:is-owner="myProfile"
|
||||
/>
|
||||
</no-ssr>
|
||||
<ds-space margin="small">
|
||||
@ -251,6 +252,17 @@
|
||||
</ds-flex>
|
||||
</ds-card>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item style="text-align: center">
|
||||
<ds-button
|
||||
v-if="myProfile"
|
||||
v-tooltip="{content: 'Create a new Post', placement: 'left', delay: { show: 500 }}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="profile-post-add-button"
|
||||
icon="plus"
|
||||
size="large"
|
||||
primary
|
||||
/>
|
||||
</ds-flex-item>
|
||||
<template v-if="activePosts.length">
|
||||
<ds-flex-item
|
||||
v-for="post in activePosts"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.download.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.delete.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.invites.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.languages.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.organizations.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ds-card :header="$t('settings.security.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Comming Soon…"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import DesignSystem from '@@'
|
||||
import '@@/styles/main.scss'
|
||||
|
||||
Vue.use(DesignSystem)
|
||||
6
plugins/styleguide.js
Normal file
6
plugins/styleguide.js
Normal file
@ -0,0 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
import '@human-connection/styleguide/dist/system.css'
|
||||
// import '@human-connection/styleguide/dist/shared.scss'
|
||||
|
||||
Vue.use(Styleguide)
|
||||
@ -1,3 +0,0 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not ie <= 8
|
||||
@ -1,14 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
extends: ['plugin:vue/strongly-recommended', '@vue/prettier'],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
}
|
||||
}
|
||||
23
styleguide/.gitignore
vendored
23
styleguide/.gitignore
vendored
@ -1,23 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
/src/system/tokens/generated
|
||||
/src/system/icons/generated
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"bracketSpacing": true
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
# CION Vue Design System
|
||||
|
||||
CION is a Design System build primary for Vue applications. You can use it as a starting point for building your own Design System.
|
||||
|
||||
The system utilizes design tokens, a living styleguide with integrated code playgrounds and reusable components for common UI tasks.
|
||||
|
||||
Living styleguide demo: https://styleguide.cion.visualjerk.de
|
||||
|
||||
Landing page demo: https://cion.visualjerk.de
|
||||
|
||||
Integrate it in your application: [Quick Start](https://github.com/visualjerk/vue-cion-design-system/wiki/Quick-Start)
|
||||
|
||||
[](https://github.com/visualjerk/vue-cion-design-system/raw/master/preview/customize.png)
|
||||
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Compiles and hot-reloads living styleguide
|
||||
|
||||
```
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
### Living styleguide
|
||||
|
||||
|
||||
Compiles living styleguide to `./docs`
|
||||
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Library
|
||||
|
||||
Compiles design system as a library to `./dist`
|
||||
|
||||
```
|
||||
yarn build:lib
|
||||
```
|
||||
|
||||
## Helper
|
||||
|
||||
### Serve living styleguide locally
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/app'],
|
||||
plugins: ['@babel/plugin-syntax-dynamic-import']
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Single Page Apps for GitHub Pages</title>
|
||||
<script type="text/javascript">
|
||||
// Single Page Apps for GitHub Pages
|
||||
// https://github.com/rafrex/spa-github-pages
|
||||
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
|
||||
// ----------------------------------------------------------------------
|
||||
// This script takes the current url and converts the path and query
|
||||
// string into just a query string, and then redirects the browser
|
||||
// to the new url with only a query string and hash fragment,
|
||||
// e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes
|
||||
// http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Note: this 404.html file must be at least 512 bytes for it to work
|
||||
// with Internet Explorer (it is currently > 512 bytes)
|
||||
// If you're creating a Project Pages site and NOT using a custom domain,
|
||||
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
|
||||
// This way the code will only replace the route part of the path, and not
|
||||
// the real directory in which the app resides, for example:
|
||||
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
|
||||
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Otherwise, leave segmentCount as 0.
|
||||
var segmentCount = 0;
|
||||
var l = window.location;
|
||||
l.replace(
|
||||
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
|
||||
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
|
||||
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
|
||||
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
|
||||
l.hash
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@ -1 +0,0 @@
|
||||
styleguide.cion.visualjerk.de
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><script src=/babel-standalone.js></script><title>CION - Vue Design System</title><link href=/css/app.e38d5069.css rel=preload as=style><link href=/css/chunk-vendors.7a428b56.css rel=preload as=style><link href=/js/app.f428b946.js rel=preload as=script><link href=/js/chunk-vendors.0a7f54fd.js rel=preload as=script><link href=/css/chunk-vendors.7a428b56.css rel=stylesheet><link href=/css/app.e38d5069.css rel=stylesheet></head><body><noscript><strong>We're sorry but this CION doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.0a7f54fd.js></script><script src=/js/app.f428b946.js></script></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,24 +0,0 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'jsx',
|
||||
'json',
|
||||
'vue'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1',
|
||||
'^@@/(.*)$': '<rootDir>/src/system/$1'
|
||||
},
|
||||
snapshotSerializers: [
|
||||
'jest-serializer-vue'
|
||||
],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)|**/spec.(js|jsx|ts|tsx)'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
{
|
||||
"name": "vue-cion-design-system",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "http-server ./docs -o -s",
|
||||
"build": "yarn theo && vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"dev": "npm-run-all --parallel theo:onchange theo servedev",
|
||||
"servedev": "vue-cli-service serve --open",
|
||||
"build:lib": "yarn theo && cross-env BUILD=library vue-cli-service build --target lib --name system ./src/library.js",
|
||||
"theo": "theo ./src/system/tokens/tokens.yml --transform web --format map.scss,scss,raw.json,json --dest ./src/system/tokens/generated",
|
||||
"theo:onchange": "onchange \"./src/system/tokens/*.yml\" -- npm run theo",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"portal-vue": "^1.5.1",
|
||||
"vue": "^2.5.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/standalone": "^7.0.0-beta.56",
|
||||
"@vue/cli-plugin-babel": "^3.0.0-rc.12",
|
||||
"@vue/cli-plugin-eslint": "^3.0.0-rc.12",
|
||||
"@vue/cli-plugin-unit-jest": "^3.0.1",
|
||||
"@vue/cli-service": "^3.0.0-rc.12",
|
||||
"@vue/eslint-config-prettier": "^4.0.1",
|
||||
"@vue/test-utils": "^1.0.0-beta.20",
|
||||
"async-validator": "^1.8.5",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-jest": "^23.0.1",
|
||||
"babel-plugin-transform-require-context": "^0.0.3",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"clipboard-copy": "^2.0.1",
|
||||
"clone-deep": "^4.0.0",
|
||||
"codemirror": "^5.39.2",
|
||||
"cross-env": "^5.2.0",
|
||||
"dot-prop": "^4.2.0",
|
||||
"lodash": "^4.17.10",
|
||||
"markdown-it": "^8.4.2",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-deflist": "^2.0.3",
|
||||
"markdown-it-emoji": "^1.4.0",
|
||||
"markdown-it-footnote": "^3.0.1",
|
||||
"markdown-it-ins": "^2.0.0",
|
||||
"markdown-it-katex": "^2.0.3",
|
||||
"markdown-it-mark": "^2.0.0",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"node-sass": "^4.9.3",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"onchange": "^4.1.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"theo": "^8.0.0-beta.2",
|
||||
"vue-click-outside": "^1.0.7",
|
||||
"vue-docgen-api": "^2.3.13",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-svg-loader": "^0.8.0",
|
||||
"vue-template-compiler": "^2.5.17",
|
||||
"vuep": "git+https://github.com/visualjerk/vuep.git#fix-iframe-firefox",
|
||||
"webpack-bundle-analyzer": "^2.13.1",
|
||||
"webpack-merge-and-include-globally": "^2.0.11"
|
||||
},
|
||||
"author": "visualjerk",
|
||||
"main": "./dist/system.umd.min.js",
|
||||
"files": [
|
||||
"dist/*",
|
||||
"src/*",
|
||||
"public/*",
|
||||
"*.json",
|
||||
"*.js"
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 298 KiB |
@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Single Page Apps for GitHub Pages</title>
|
||||
<script type="text/javascript">
|
||||
// Single Page Apps for GitHub Pages
|
||||
// https://github.com/rafrex/spa-github-pages
|
||||
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
|
||||
// ----------------------------------------------------------------------
|
||||
// This script takes the current url and converts the path and query
|
||||
// string into just a query string, and then redirects the browser
|
||||
// to the new url with only a query string and hash fragment,
|
||||
// e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes
|
||||
// http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Note: this 404.html file must be at least 512 bytes for it to work
|
||||
// with Internet Explorer (it is currently > 512 bytes)
|
||||
// If you're creating a Project Pages site and NOT using a custom domain,
|
||||
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
|
||||
// This way the code will only replace the route part of the path, and not
|
||||
// the real directory in which the app resides, for example:
|
||||
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
|
||||
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Otherwise, leave segmentCount as 0.
|
||||
var segmentCount = 0;
|
||||
var l = window.location;
|
||||
l.replace(
|
||||
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
|
||||
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
|
||||
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
|
||||
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
|
||||
l.hash
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@ -1 +0,0 @@
|
||||
styleguide.cion.visualjerk.de
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<script src="/babel-standalone.js"></script>
|
||||
<title>Human Connection - Styleguide</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but this CION doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
@ -1,8 +0,0 @@
|
||||
import system from './system'
|
||||
import { tokens } from './system/tokens'
|
||||
import * as utils from './system/utils'
|
||||
import * as mixins from './system/mixins'
|
||||
|
||||
export { tokens, utils, mixins }
|
||||
|
||||
export default system
|
||||
@ -1,9 +0,0 @@
|
||||
module.exports = function(source, map) {
|
||||
this.callback(
|
||||
null,
|
||||
`export default function (Component) {
|
||||
Component.options.__docs = ${JSON.stringify(source)}
|
||||
}`,
|
||||
map
|
||||
)
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
module.exports = function(source, map) {
|
||||
this.callback(
|
||||
null,
|
||||
`export default function () {}`,
|
||||
map
|
||||
)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user