merged tags and categories in

This commit is contained in:
Grzegorz Leoniec 2018-12-08 13:44:22 +01:00
parent 987fa33d58
commit c96e22492c
No known key found for this signature in database
GPG Key ID: 3AA43686D4EB1377
14 changed files with 367 additions and 41 deletions

View File

@ -118,3 +118,11 @@ blockquote {
margin-top: 0;
}
}
hr {
border: 0;
width: 100%;
color: $color-neutral-80;
background-color: $color-neutral-80;
height: 1px !important;
}

View File

@ -31,13 +31,22 @@
</no-ssr>
</ds-space>
<template slot="footer">
<span :style="{ opacity: post.shoutedCount ? 1 : .5 }">
<ds-icon name="heart-o" /> <small>{{ post.shoutedCount }}</small>
</span>
&nbsp;
<span :style="{ opacity: post.commentsCount ? 1 : .5 }">
<ds-icon name="comments" /> <small>{{ post.commentsCount }}</small>
</span>
<div style="display: inline-block; opacity: .5;">
<ds-icon
v-tooltip="{content: category.name, placement: 'bottom-start', delay: { show: 500 }}"
v-for="category in post.categories"
:key="category.id"
:name="category.icon" />&nbsp;
</div>
<div style="display: inline-block; float: right">
<span :style="{ opacity: post.shoutedCount ? 1 : .5 }">
<ds-icon name="bullhorn" /> <small>{{ post.shoutedCount }}</small>
</span>
&nbsp;
<span :style="{ opacity: post.commentsCount ? 1 : .5 }">
<ds-icon name="comments" /> <small>{{ post.commentsCount }}</small>
</span>
</div>
</template>
</ds-card>
</a>

View File

@ -7,9 +7,8 @@
:disabled="disabled || loading"
danger
size="x-large"
icon="heart"
@click="shout"
/>
icon="bullhorn"
@click="shout" />
<ds-space margin-bottom="xx-small" />
<ds-text color="soft">
<ds-heading

View File

@ -6,14 +6,8 @@ export default gql(`
id
name
avatar
about
createdAt
friendsCount
friends {
id
name
slug
avatar
}
badges {
id
key
@ -63,6 +57,11 @@ export default gql(`
deleted
image
createdAt
categories {
id
name
icon
}
author {
id
avatar

View File

@ -48,6 +48,10 @@ export default {
name: 'Categories',
path: `/admin/categories`
},
{
name: 'Tags',
path: `/admin/tags`
},
{
name: 'Settings',
path: `/admin/settings`

View File

@ -1,7 +1,42 @@
<template>
<ds-card>
<ds-space margin="small">
Categories...
</ds-space>
<ds-card space="small">
<ds-heading tag="h3">Themen / Kategorien</ds-heading>
<ds-table
:data="Category"
:fields="['icon', 'name', 'postCount']"
condensed>
<template
slot="icon"
slot-scope="scope">
<ds-icon :name="scope.row.icon" />
</template>
</ds-table>
</ds-card>
</template>
<script>
import gql from 'graphql-tag'
export default {
data() {
return {
Category: []
}
},
apollo: {
Category: {
query: gql(`
query {
Category(orderBy: postCount_desc) {
id
name
slug
icon
postCount
}
}
`)
}
}
}
</script>

47
pages/admin/tags.vue Normal file
View File

@ -0,0 +1,47 @@
<template>
<ds-card space="small">
<ds-heading tag="h3">Tags</ds-heading>
<ds-table
:data="Tag"
:fields="fields"
condensed>
<template
slot="id"
slot-scope="scope">
{{ scope.index + 1 }}
</template>
</ds-table>
</ds-card>
</template>
<script>
import gql from 'graphql-tag'
export default {
data() {
return {
Tag: [],
fields: {
id: { label: '#' },
name: { label: 'Name' },
taggedCountUnique: { label: 'Nutzer' },
taggedCount: { label: 'Beiträge' }
}
}
},
apollo: {
Tag: {
query: gql(`
query {
Tag(first: 20, orderBy: taggedCountUnique_desc) {
id
name
taggedCount
taggedCountUnique
}
}
`)
}
}
}
</script>

View File

@ -107,6 +107,7 @@ export default {
categories {
id
name
icon
}
shoutedCount
}

View File

@ -23,7 +23,14 @@
:post-id="post.id"
/>
<!-- Categories -->
<div class="tags">
<ds-icon
v-tooltip="{content: category.name, placement: 'top-start', delay: { show: 300 }}"
v-for="category in post.categories"
:key="category.id"
:name="category.icon"
size="large" />&nbsp;
<ds-space margin-bottom="small" />
<!--<div class="tags">
<ds-icon name="compass" /> <ds-tag
v-for="category in post.categories"
:key="category.id"
@ -163,7 +170,7 @@ export default {
name
}
commentsCount
comments(orderBy: _id_desc) {
comments(orderBy: createdAt_desc) {
id
contentExcerpt
createdAt
@ -187,6 +194,7 @@ export default {
categories {
id
name
icon
}
shoutedCount
}

View File

@ -7,7 +7,8 @@
<ds-space />
<h3><ds-icon name="compass" /> Themenkategorien</h3>
<div class="tags">
<ds-tag
<ds-icon
v-tooltip="{content: category.name, placement: 'top-start', delay: { show: 300 }}"
v-for="category in post.categories"
:key="category.id"
>
@ -81,6 +82,7 @@ export default {
categories {
id
name
icon
}
relatedContributions(first: 2) {
id
@ -89,6 +91,11 @@ export default {
contentExcerpt
shoutedCount
commentsCount
categories {
id
name
icon
}
author {
id
name

View File

@ -28,9 +28,8 @@
<ds-text
align="center"
color="soft"
size="small"
>
Mitglied seid {{ user.createdAt | date('MMMM yyyy') }}
size="small">
Mitglied seit {{ user.createdAt | date('MMMM yyyy') }}
</ds-text>
</ds-space>
<ds-space

View File

@ -1,5 +1,203 @@
<template>
<ds-card>
<p>My Data...</p>
<ds-card space="small">
<ds-input
id="name"
v-model="form.name"
icon="user"
label="Dein Name"
placeholder="Dein Name"/>
<ds-select
id="city"
:options="cities"
v-model="city"
icon="map-marker"
label="Deine Stadt"
placeholder="Deine Stadt"
@input="handleCitySelection"
@input.native="handleCityInput" />
<ds-input
id="bio"
v-model="form.about"
type="textarea"
rows="3"
label="Erzähl doch ein wenig (in zwei Sätzen) über dich"
placeholder="Über mich"/>
<template slot="footer">
<ds-button
style="float: right;"
icon="check"
primary
@click.prevent="submit">Speichern</ds-button>
</template>
</ds-card>
</template>
<script>
import gql from 'graphql-tag'
import { mapGetters } from 'vuex'
import { CancelToken } from 'axios'
import find from 'lodash/find'
let timeout
const mapboxToken =
'pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ'
export default {
data() {
return {
axiosSource: null,
cities: [],
city: null,
form: {
name: null,
locationId: null,
about: null
}
}
},
computed: {
...mapGetters({
user: 'auth/user'
})
},
watch: {
user: {
immediate: true,
handler: function(user) {
this.form = {
name: user.name,
locationId: user.locationId,
about: user.about
}
}
}
},
methods: {
submit() {
console.log('SUBMIT', { ...this.form })
this.$apollo
.mutate({
mutation: gql`
mutation(
$id: ID!
$name: String
$locationId: String
$about: String
) {
UpdateUser(
id: $id
name: $name
locationId: $locationId
about: $about
) {
id
name
locationId
about
}
}
`,
// Parameters
variables: {
id: this.user.id,
name: this.form.name,
locationId: this.form.locationId,
about: this.form.about
},
// Update the cache with the result
// The query will be updated with the optimistic response
// and then with the real result of the mutation
update: (store, { data: { UpdateUser } }) => {
// this.$store.dispatch('auth/refresh', UpdateUser)
// Read the data from our cache for this query.
// const data = store.readQuery({ query: TAGS_QUERY })
// Add our tag from the mutation to the end
// data.tags.push(addTag)
// Write our data back to the cache.
// store.writeQuery({ query: TAGS_QUERY, data })
}
// Optimistic UI
// Will be treated as a 'fake' result as soon as the request is made
// so that the UI can react quickly and the user be happy
/* optimisticResponse: {
__typename: 'Mutation',
addTag: {
__typename: 'Tag',
id: -1,
label: newTag
}
} */
})
.then(data => {
console.log(data)
this.$toast.success('Updated user')
})
.catch(err => {
console.error(err)
this.$toast.error(err.message)
})
},
handleCityInput(value) {
clearTimeout(timeout)
timeout = setTimeout(() => this.requestGeoData(value), 500)
},
handleCitySelection(value) {
console.log('SET CURRENT VALUE', value)
const item = find(this.cities, { value: value })
console.log('ID:', item.id)
this.form.locationId = item.id
},
handleCityEnter() {
console.log('SET CURRENT VALUE')
},
processCityResults(res) {
if (
!res ||
!res.data ||
!res.data.features ||
!res.data.features.length
) {
return []
}
let output = []
res.data.features.forEach(item => {
output.push({
label: item.place_name,
value: item.place_name,
id: item.id
})
})
return output
},
requestGeoData(e) {
if (this.axiosSource) {
// cancel last request
this.axiosSource.cancel()
}
const value = e.target ? e.target.value.trim() : ''
if (value === '' || value.length < 3) {
this.cities = []
return
}
this.axiosSource = CancelToken.source()
this.$axios
.get(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${value}.json?access_token=${mapboxToken}&types=region,postcode,district,place,country&language=de`,
{
cancelToken: this.axiosSource.token
}
)
.then(res => {
this.cities = this.processCityResults(res)
})
console.log('TRY TO GET DATA FOR ', value)
}
}
}
</script>

View File

@ -15,7 +15,6 @@
color: $text-color-base;
background: $background-color-base;
border: $input-border-size solid $border-color-base;
border-radius: $border-radius-base;
outline: none;
@ -24,25 +23,21 @@
&::placeholder {
color: $text-color-disabled;
}
.ds-input-has-focus &,
&:focus {
border-color: $border-color-active;
background: $background-color-base;
}
.ds-input-is-disabled &,
&:disabled {
color: $text-color-disabled;
opacity: $opacity-disabled;
cursor: not-allowed;
}
.ds-input-has-error & {
border-color: $border-color-danger;
}
}
.ds-input-size-small {
font-size: $font-size-small;
@ -52,7 +47,6 @@
padding: $input-padding-vertical-small $space-x-small;
}
}
.ds-input-size-large {
font-size: $font-size-large;
@ -90,6 +84,15 @@
}
}
.ds-input-size-small & {
width: $input-height-small;
}
.ds-input-size-large & {
width: $input-height-large;
}
}
.#{$class}-icon-right {
right: 0;
left: auto;
@ -102,6 +105,10 @@
padding-left: $input-height-small;
}
.ds-input-size-small & {
padding-left: $input-height-small;
}
.ds-input-size-large & {
padding-left: $input-height-large;
}
@ -117,5 +124,9 @@
.ds-input-size-large & {
padding-right: $input-height-large;
}
.ds-input-size-large & {
padding-right: $input-height-large;
}
}
}

View File

@ -952,7 +952,6 @@
"@nuxtjs/proxy@^1.3.0":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-1.3.1.tgz#7d76179aff321491f126d6560434579a4dc7a89a"
integrity sha512-agcTJVRCY0XfZcGV573bdIQLsg9fr5p6zikpxtUzR3xywdUBJ+JMKAiz3ew15bOZGK8lVS8u/PBmZ33iEhr3rg==
dependencies:
consola "^1.4.4"
http-proxy-middleware "^0.19.0"
@ -1876,14 +1875,12 @@ aws4@^1.8.0:
axios-retry@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.1.tgz#88d2971f671a9023b21d887c5dcac6c54f332cde"
integrity sha512-BeNOxa/CBQQLa9gVuMta1oWIhbL6UETKBfAmFjOXwiBxgcmrDBVVwz/gKZTpzKJlVjmi5DeYC+lP5Ng7ssc1pg==
dependencies:
is-retry-allowed "^1.1.0"
axios@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=
resolved "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
dependencies:
follow-redirects "^1.3.0"
is-buffer "^1.1.5"
@ -3317,7 +3314,12 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7:
core-js@^2.4.0, core-js@^2.5.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.0.tgz#1e30793e9ee5782b307e37ffa22da0eacddd84d4"
integrity sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==
core-js@^2.5.7:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==
@ -3734,7 +3736,6 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"