mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Some important commit messages:
```
Fix youtu.be not being embedded
And also try to maintain the old behaviour matching
`provider.provider_url`.
```
```
Remove confusing code comments and obsolete code
I discovered that the behaviour of no duplicate notifications being send
out is caused by the frontend: When the editor reads html from the
backend, it will parse hashtags and mentions as ordinary links, not as
their respective nodes during editing. Also, we don't have to worry
about duplicate ids being found: The cypher statement will implicitly
suppress duplicate notification nodes for the same user.
So let's remove the code to avoid confusing the next developer.
```
```
Test editor.getHTML()
I do this because I'm not able to test the content of `this.editor` from
a wrapper of `vue-test-utils`. If I call `this.editor.getHTML` directly
and use it as a computed property `renderedContent` to populate a `<div
v-html="renderedContent" />` this will not work for the embeds. So, my
current best bet is to test the editor object isolated from a real
component. ;(
```
```
Add core-js as explicit dependency
Because of build errors on Travis.
See: https://stackoverflow.com/a/55313456
Remove as soon as this issue is resolved:
https://github.com/storybookjs/storybook/issues/7591
```
```
Refactor: Keep Runtime-only builds
See: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
```
365 lines
10 KiB
Vue
365 lines
10 KiB
Vue
<template>
|
||
<div class="layout-default">
|
||
<div class="main-navigation">
|
||
<ds-container class="main-navigation-container" style="padding: 10px 10px;">
|
||
<div>
|
||
<ds-flex class="main-navigation-flex">
|
||
<ds-flex-item :width="{ lg: '3.5%' }" />
|
||
<ds-flex-item :width="{ base: '80%', sm: '80%', md: '80%', lg: '15%' }">
|
||
<a @click="redirectToRoot">
|
||
<ds-logo />
|
||
</a>
|
||
</ds-flex-item>
|
||
<ds-flex-item
|
||
:width="{ base: '20%', sm: '20%', md: '20%', lg: '0%' }"
|
||
class="mobile-hamburger-menu"
|
||
>
|
||
<ds-button icon="bars" @click="toggleMobileMenuView" right />
|
||
</ds-flex-item>
|
||
<ds-flex-item
|
||
:width="{ base: '85%', sm: '85%', md: '50%', lg: '50%' }"
|
||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||
>
|
||
<div id="nav-search-box">
|
||
<search-input
|
||
id="nav-search"
|
||
:delay="300"
|
||
:pending="quickSearchPending"
|
||
:results="quickSearchResults"
|
||
@clear="quickSearchClear"
|
||
@search="value => quickSearch({ value })"
|
||
@select="goToPost"
|
||
/>
|
||
</div>
|
||
</ds-flex-item>
|
||
<ds-flex-item
|
||
:width="{ base: '15%', sm: '15%', md: '10%', lg: '10%' }"
|
||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||
>
|
||
<no-ssr>
|
||
<filter-posts placement="top-start" offset="8" :categories="categories" />
|
||
</no-ssr>
|
||
</ds-flex-item>
|
||
<ds-flex-item :width="{ base: '100%', sm: '100%', md: '10%', lg: '2%' }" />
|
||
<ds-flex-item
|
||
:width="{ base: '100%', sm: '100%', md: '100%', lg: '13%' }"
|
||
style="background-color:white"
|
||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||
>
|
||
<div
|
||
class="main-navigation-right"
|
||
:class="{
|
||
'desktop-view': !toggleMobileMenu,
|
||
'hide-mobile-menu': !toggleMobileMenu,
|
||
}"
|
||
>
|
||
<no-ssr>
|
||
<locale-switch class="topbar-locale-switch" placement="top" offset="8" />
|
||
</no-ssr>
|
||
<template v-if="isLoggedIn">
|
||
<no-ssr>
|
||
<notification-menu placement="top" />
|
||
</no-ssr>
|
||
<no-ssr>
|
||
<dropdown class="avatar-menu" offset="8">
|
||
<template slot="default" slot-scope="{ toggleMenu }">
|
||
<a
|
||
class="avatar-menu-trigger"
|
||
:href="
|
||
$router.resolve({
|
||
name: 'profile-id-slug',
|
||
params: { id: user.id, slug: user.slug },
|
||
}).href
|
||
"
|
||
@click.prevent="toggleMenu"
|
||
>
|
||
<hc-avatar :user="user" />
|
||
<ds-icon size="xx-small" name="angle-down" />
|
||
</a>
|
||
</template>
|
||
<template slot="popover" slot-scope="{ closeMenu }">
|
||
<div class="avatar-menu-popover">
|
||
{{ $t('login.hello') }}
|
||
<b>{{ userName }}</b>
|
||
<template v-if="user.role !== 'user'">
|
||
<ds-text color="softer" size="small" style="margin-bottom: 0">
|
||
{{ user.role | camelCase }}
|
||
</ds-text>
|
||
</template>
|
||
<hr />
|
||
<ds-menu :routes="routes" :matcher="matcher">
|
||
<ds-menu-item
|
||
slot="menuitem"
|
||
slot-scope="item"
|
||
:route="item.route"
|
||
:parents="item.parents"
|
||
@click.native="closeMenu(false)"
|
||
>
|
||
<ds-icon :name="item.route.icon" />
|
||
{{ item.route.name }}
|
||
</ds-menu-item>
|
||
</ds-menu>
|
||
<hr />
|
||
<nuxt-link class="logout-link" :to="{ name: 'logout' }">
|
||
<ds-icon name="sign-out" />
|
||
{{ $t('login.logout') }}
|
||
</nuxt-link>
|
||
</div>
|
||
</template>
|
||
</dropdown>
|
||
</no-ssr>
|
||
</template>
|
||
</div>
|
||
</ds-flex-item>
|
||
</ds-flex>
|
||
</div>
|
||
</ds-container>
|
||
</div>
|
||
<ds-container style="word-break: break-all">
|
||
<div class="main-container">
|
||
<nuxt />
|
||
</div>
|
||
</ds-container>
|
||
<div id="footer" class="ds-footer">
|
||
<a href="https://human-connection.org" target="_blank" v-html="$t('site.made')"></a>
|
||
-
|
||
<nuxt-link to="/imprint">{{ $t('site.imprint') }}</nuxt-link>
|
||
‑
|
||
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAc') }}</nuxt-link>
|
||
‑
|
||
<nuxt-link to="/privacy">{{ $t('site.privacy') }}</nuxt-link>
|
||
‑
|
||
<nuxt-link to="/changelog">{{ $t('site.changelog') }}</nuxt-link>
|
||
</div>
|
||
<div id="overlay" />
|
||
<no-ssr>
|
||
<modal />
|
||
</no-ssr>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { mapGetters, mapActions } from 'vuex'
|
||
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||
import SearchInput from '~/components/SearchInput.vue'
|
||
import Modal from '~/components/Modal'
|
||
import NotificationMenu from '~/components/notifications/NotificationMenu'
|
||
import Dropdown from '~/components/Dropdown'
|
||
import HcAvatar from '~/components/Avatar/Avatar.vue'
|
||
import seo from '~/mixins/seo'
|
||
import FilterPosts from '~/components/FilterPosts/FilterPosts.vue'
|
||
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||
|
||
export default {
|
||
components: {
|
||
Dropdown,
|
||
LocaleSwitch,
|
||
SearchInput,
|
||
Modal,
|
||
NotificationMenu,
|
||
HcAvatar,
|
||
FilterPosts,
|
||
},
|
||
mixins: [seo],
|
||
data() {
|
||
return {
|
||
mobileSearchVisible: false,
|
||
toggleMobileMenu: false,
|
||
categories: [],
|
||
}
|
||
},
|
||
computed: {
|
||
...mapGetters({
|
||
user: 'auth/user',
|
||
isLoggedIn: 'auth/isLoggedIn',
|
||
isModerator: 'auth/isModerator',
|
||
isAdmin: 'auth/isAdmin',
|
||
quickSearchResults: 'search/quickResults',
|
||
quickSearchPending: 'search/quickPending',
|
||
}),
|
||
userName() {
|
||
const { name } = this.user || {}
|
||
return name || this.$t('profile.userAnonym')
|
||
},
|
||
routes() {
|
||
if (!this.user.slug) {
|
||
return []
|
||
}
|
||
let routes = [
|
||
{
|
||
name: this.$t('profile.name'),
|
||
path: `/profile/${this.user.slug}`,
|
||
icon: 'user',
|
||
},
|
||
{
|
||
name: this.$t('settings.name'),
|
||
path: `/settings`,
|
||
icon: 'cogs',
|
||
},
|
||
]
|
||
if (this.isModerator) {
|
||
routes.push({
|
||
name: this.$t('moderation.name'),
|
||
path: `/moderation`,
|
||
icon: 'balance-scale',
|
||
})
|
||
}
|
||
if (this.isAdmin) {
|
||
routes.push({
|
||
name: this.$t('admin.name'),
|
||
path: `/admin`,
|
||
icon: 'shield',
|
||
})
|
||
}
|
||
return routes
|
||
},
|
||
},
|
||
watch: {
|
||
Category(category) {
|
||
this.categories = category || []
|
||
},
|
||
},
|
||
methods: {
|
||
...mapActions({
|
||
quickSearchClear: 'search/quickClear',
|
||
quickSearch: 'search/quickSearch',
|
||
fetchPosts: 'posts/fetchPosts',
|
||
}),
|
||
goToPost(item) {
|
||
this.$nextTick(() => {
|
||
this.$router.push({
|
||
name: 'post-id-slug',
|
||
params: { id: item.id, slug: item.slug },
|
||
})
|
||
})
|
||
},
|
||
matcher(url, route) {
|
||
if (url.indexOf('/profile') === 0) {
|
||
// do only match own profile
|
||
return this.$route.path === url
|
||
}
|
||
return this.$route.path.indexOf(url) === 0
|
||
},
|
||
toggleMobileMenuView() {
|
||
this.toggleMobileMenu = !this.toggleMobileMenu
|
||
},
|
||
redirectToRoot() {
|
||
this.$router.replace('/')
|
||
this.fetchPosts({ i18n: this.$i18n, filter: {} })
|
||
},
|
||
},
|
||
apollo: {
|
||
Category: {
|
||
query() {
|
||
return CategoryQuery()
|
||
},
|
||
fetchPolicy: 'cache-and-network',
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.topbar-locale-switch {
|
||
display: flex;
|
||
margin-right: $space-xx-small;
|
||
align-self: center;
|
||
display: inline-flex;
|
||
}
|
||
|
||
.main-container {
|
||
padding-top: 6rem;
|
||
padding-bottom: 5rem;
|
||
}
|
||
|
||
.main-navigation {
|
||
a {
|
||
color: $text-color-soft;
|
||
}
|
||
}
|
||
|
||
.main-navigation-right {
|
||
display: flex;
|
||
flex: 1;
|
||
}
|
||
|
||
.main-navigation-right .desktop-view {
|
||
float: right;
|
||
}
|
||
|
||
.avatar-menu {
|
||
margin: 2px 0px 0px 5px;
|
||
}
|
||
|
||
.avatar-menu-trigger {
|
||
user-select: none;
|
||
display: flex;
|
||
align-items: center;
|
||
padding-left: $space-xx-small;
|
||
}
|
||
|
||
.avatar-menu-popover {
|
||
padding-top: 0.5rem;
|
||
padding-bottom: 0.5rem;
|
||
|
||
hr {
|
||
color: $color-neutral-90;
|
||
background-color: $color-neutral-90;
|
||
}
|
||
|
||
.logout-link {
|
||
margin-left: -$space-small;
|
||
margin-right: -$space-small;
|
||
margin-top: -$space-xxx-small;
|
||
margin-bottom: -$space-x-small;
|
||
padding: $space-x-small $space-small;
|
||
// subtract menu border with from padding
|
||
padding-left: $space-small - 2;
|
||
|
||
color: $text-color-base;
|
||
|
||
&:hover {
|
||
color: $text-color-link-active;
|
||
}
|
||
}
|
||
|
||
nav {
|
||
margin-left: -$space-small;
|
||
margin-right: -$space-small;
|
||
margin-top: -$space-xx-small;
|
||
margin-bottom: -$space-xx-small;
|
||
|
||
a {
|
||
padding-left: 12px;
|
||
}
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 960px) {
|
||
.mobile-hamburger-menu {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
@media only screen and (max-width: 960px) {
|
||
#nav-search-box,
|
||
.main-navigation-right {
|
||
margin: 10px 0px;
|
||
}
|
||
|
||
.hide-mobile-menu {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.ds-footer {
|
||
text-align: center;
|
||
position: fixed;
|
||
bottom: 0px;
|
||
z-index: 10;
|
||
background-color: white;
|
||
width: 100%;
|
||
padding: 10px 10px;
|
||
}
|
||
</style>
|