mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Separate concerns in components
- SearchResources is a feature component that handles communication with the backend and fetches the search results - Those results are passed to SearchableInput which displays the results in a ds-select dropdown and handles interacting with them - SearchInput renders the SearchHeading, SearchPost, and HcUser generic components - Would love to make the SearchableInput more generic and reusable, or create a new reusable component for this, but I think this will happen just when we migrate the Search.vue from the styleguide Co-authored-by: Moriz Wahl <moriz.wahl@gmx.de>
This commit is contained in:
parent
2242c001b4
commit
d74d2072ba
@ -1,50 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ds-flex-item class="search-option">
|
|
||||||
<ds-avatar class="avatar" name="option.name" image="option.avatar" />
|
|
||||||
<div>
|
|
||||||
<ds-text class="userinfo">
|
|
||||||
<b class="username">{{ option.name | truncate(70) }}</b>
|
|
||||||
</ds-text>
|
|
||||||
</div>
|
|
||||||
<ds-text align="left" size="small" color="soft">@{{ option.slug | truncate(70) }}</ds-text>
|
|
||||||
</ds-flex-item>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'SearchUser',
|
|
||||||
props: {
|
|
||||||
option: { type: Object, required: true },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.avatar {
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
margin-right: 4px;
|
|
||||||
height: 100%;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.userinfo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
> .ds-text {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: $space-xx-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.user {
|
|
||||||
white-space: nowrap;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
&:hover,
|
|
||||||
&.active {
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.username {
|
|
||||||
color: #17b53f;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import SearchInput from './SearchInput.vue'
|
import SearchResources from './SearchResources.vue'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
localVue.filter('truncate', () => 'truncated string')
|
localVue.filter('truncate', () => 'truncated string')
|
||||||
localVue.filter('dateTime', () => Date.now)
|
localVue.filter('dateTime', () => Date.now)
|
||||||
|
|
||||||
describe('SearchInput.vue', () => {
|
describe('SearchResources.vue', () => {
|
||||||
let mocks
|
let mocks
|
||||||
let propsData
|
let propsData
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ describe('SearchInput.vue', () => {
|
|||||||
mocks = {
|
mocks = {
|
||||||
$t: () => {},
|
$t: () => {},
|
||||||
}
|
}
|
||||||
return mount(SearchInput, { mocks, localVue, propsData })
|
return mount(SearchResources, { mocks, localVue, propsData })
|
||||||
}
|
}
|
||||||
|
|
||||||
it('renders', () => {
|
it('renders', () => {
|
||||||
@ -27,7 +27,7 @@ describe('SearchInput.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('has id "nav-search"', () => {
|
it('has id "nav-search"', () => {
|
||||||
expect(Wrapper().contains('#nav-search')).toBe(true)
|
expect(Wrapper().contains('[data-test="search-resources"]')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('defaults to an empty value', () => {
|
it('defaults to an empty value', () => {
|
||||||
@ -82,9 +82,9 @@ describe('SearchInput.vue', () => {
|
|||||||
expect(wrapper.emitted().clear.length).toBe(1)
|
expect(wrapper.emitted().clear.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('changes the unprocessedSearchInput as the value changes', () => {
|
it('changes the unprocessedSearchResources as the value changes', () => {
|
||||||
select.trigger('input')
|
select.trigger('input')
|
||||||
expect(wrapper.vm.unprocessedSearchInput).toBe('abcd')
|
expect(wrapper.vm.unprocessedSearchResources).toBe('abcd')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('searches for the term when enter is pressed', async () => {
|
it('searches for the term when enter is pressed', async () => {
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { storiesOf } from '@storybook/vue'
|
import { storiesOf } from '@storybook/vue'
|
||||||
import { withA11y } from '@storybook/addon-a11y'
|
import { withA11y } from '@storybook/addon-a11y'
|
||||||
import SearchInput from './SearchInput.vue'
|
import SearchResources from './SearchResources.vue'
|
||||||
import helpers from '~/storybook/helpers'
|
import helpers from '~/storybook/helpers'
|
||||||
|
|
||||||
helpers.init()
|
helpers.init()
|
||||||
@ -104,7 +104,7 @@ storiesOf('Search Input', module)
|
|||||||
.addDecorator(withA11y)
|
.addDecorator(withA11y)
|
||||||
.addDecorator(helpers.layout)
|
.addDecorator(helpers.layout)
|
||||||
.add('test', () => ({
|
.add('test', () => ({
|
||||||
components: { SearchInput },
|
components: { SearchResources },
|
||||||
store: helpers.store,
|
store: helpers.store,
|
||||||
data: () => ({
|
data: () => ({
|
||||||
results: results,
|
results: results,
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<searchable-input
|
||||||
|
data-test="search-resources"
|
||||||
|
id="search-resources"
|
||||||
|
:loading="pending"
|
||||||
|
:options="searchResults"
|
||||||
|
@query="query"
|
||||||
|
@clearSearch="clear"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { findResourcesQuery } from '~/graphql/Search.js'
|
||||||
|
import SearchableInput from '~/components/generic/SearchableInput/SearchableInput.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SearchableInput,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
searchResults: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async query(value) {
|
||||||
|
this.pending = true
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { findResources },
|
||||||
|
} = await this.$apollo.query({
|
||||||
|
query: findResourcesQuery,
|
||||||
|
variables: {
|
||||||
|
query: value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
this.searchResults = findResources
|
||||||
|
} catch (error) {
|
||||||
|
this.searchResults = []
|
||||||
|
} finally {
|
||||||
|
this.pending = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.pending = false
|
||||||
|
this.searchResults = []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -13,4 +13,3 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style></style>
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-flex class="post-search-item">
|
<ds-flex class="search-post">
|
||||||
<ds-flex-item class="search-option-label">
|
<ds-flex-item class="search-option-label">
|
||||||
<ds-text>{{ option.title | truncate(70) }}</ds-text>
|
<ds-text>{{ option.title | truncate(70) }}</ds-text>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
@ -35,8 +35,27 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style lang="scss">
|
||||||
.post-search-item {
|
.search-post {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.search-option-label {
|
||||||
|
align-self: center;
|
||||||
|
padding-left: $space-x-small;
|
||||||
|
}
|
||||||
|
.search-option-meta {
|
||||||
|
align-self: center;
|
||||||
|
.ds-flex {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search-meta {
|
||||||
|
float: right;
|
||||||
|
padding-top: 2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: none;
|
||||||
|
.base-icon {
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="search"
|
class="searchable-input"
|
||||||
aria-label="search"
|
aria-label="search"
|
||||||
role="search"
|
role="search"
|
||||||
:class="{
|
:class="{
|
||||||
@ -12,149 +12,141 @@
|
|||||||
<div class="control">
|
<div class="control">
|
||||||
<a v-if="isActive" class="search-clear-btn" @click="clear"> </a>
|
<a v-if="isActive" class="search-clear-btn" @click="clear"> </a>
|
||||||
<ds-select
|
<ds-select
|
||||||
:id="id"
|
|
||||||
ref="input"
|
ref="input"
|
||||||
v-model="searchValue"
|
|
||||||
class="input"
|
class="input"
|
||||||
name="search"
|
name="search"
|
||||||
type="search"
|
type="search"
|
||||||
icon="search"
|
icon="search"
|
||||||
|
v-model="searchValue"
|
||||||
|
:id="id"
|
||||||
label-prop="id"
|
label-prop="id"
|
||||||
:no-options-available="emptyText"
|
|
||||||
:icon-right="isActive ? 'close' : null"
|
:icon-right="isActive ? 'close' : null"
|
||||||
|
:options="options"
|
||||||
|
:loading="loading"
|
||||||
:filter="item => item"
|
:filter="item => item"
|
||||||
:options="searchResults"
|
:no-options-available="emptyText"
|
||||||
:auto-reset-search="!searchValue"
|
:auto-reset-search="!searchValue"
|
||||||
:placeholder="$t('search.placeholder')"
|
:placeholder="$t('search.placeholder')"
|
||||||
:loading="pending"
|
@click.capture.native="isOpen = true"
|
||||||
@keyup.enter.native="onEnter"
|
|
||||||
@focus.capture.native="onFocus"
|
@focus.capture.native="onFocus"
|
||||||
@blur.capture.native="onBlur"
|
@input.native="handleInput"
|
||||||
|
@keyup.enter.native="onEnter"
|
||||||
@keyup.delete.native="onDelete"
|
@keyup.delete.native="onDelete"
|
||||||
@keyup.esc.native="clear"
|
@keyup.esc.native="clear"
|
||||||
|
@blur.capture.native="onBlur"
|
||||||
@input.exact="onSelect"
|
@input.exact="onSelect"
|
||||||
@input.native="handleInput"
|
|
||||||
@click.capture.native="isOpen = true"
|
|
||||||
>
|
>
|
||||||
<template slot="option" slot-scope="{ option }">
|
<template slot="option" slot-scope="{ option }">
|
||||||
<ds-flex v-if="isFirstOfType(option)" class="search-option-heading">
|
<span v-if="isFirstOfType(option)" class="search-heading">
|
||||||
<search-heading :resource-type="option.__typename" />
|
<search-heading :resource-type="option.__typename" />
|
||||||
</ds-flex>
|
</span>
|
||||||
<ds-flex
|
<span
|
||||||
v-if="option.__typename === 'User'"
|
v-if="option.__typename === 'User'"
|
||||||
:class="{ 'extra-space': isFirstOfType(option) }"
|
:class="{ 'extra-space': isFirstOfType(option), 'flex-span': true }"
|
||||||
>
|
>
|
||||||
<search-user :option="option" />
|
<hc-user :user="option" :showPopover="false" />
|
||||||
</ds-flex>
|
</span>
|
||||||
<ds-flex
|
<span
|
||||||
v-if="option.__typename === 'Post'"
|
v-if="option.__typename === 'Post'"
|
||||||
:class="{ 'extra-space': isFirstOfType(option) }"
|
:class="{ 'extra-space': isFirstOfType(option), 'flex-span': true }"
|
||||||
>
|
>
|
||||||
<search-post :option="option" />
|
<search-post :option="option" />
|
||||||
</ds-flex>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</ds-select>
|
</ds-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { findResourcesQuery } from '~/graphql/Search.js'
|
import SearchHeading from '~/components/generic/SearchHeading/SearchHeading.vue'
|
||||||
import SearchHeading from './SearchHeading.vue'
|
import SearchPost from '~/components/generic/SearchPost/SearchPost.vue'
|
||||||
import SearchPost from './SearchPost.vue'
|
import HcUser from '~/components/User/User.vue'
|
||||||
import SearchUser from './SearchUser.vue'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SearchHeading,
|
SearchHeading,
|
||||||
SearchPost,
|
SearchPost,
|
||||||
SearchUser,
|
HcUser,
|
||||||
},
|
},
|
||||||
name: 'SearchInput',
|
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: { type: String },
|
||||||
type: String,
|
loading: { type: Boolean, default: false },
|
||||||
default: 'nav-search',
|
options: { type: Array, default: () => [] },
|
||||||
},
|
|
||||||
delay: {
|
|
||||||
type: Number,
|
|
||||||
default: 300,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchProcess: null,
|
|
||||||
value: '',
|
|
||||||
pending: false,
|
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
lastSearchTerm: '',
|
|
||||||
unprocessedSearchInput: '',
|
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
quickValue: '',
|
value: '',
|
||||||
searchResults: [],
|
unprocessedSearchInput: '',
|
||||||
|
searchProcess: null,
|
||||||
|
lastSearchTerm: '',
|
||||||
|
delay: 300,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// #: Unused at the moment?
|
|
||||||
isActive() {
|
|
||||||
return !isEmpty(this.lastSearchTerm)
|
|
||||||
},
|
|
||||||
emptyText() {
|
emptyText() {
|
||||||
return this.isActive && !this.pending ? this.$t('search.failed') : this.$t('search.hint')
|
return this.isActive && !this.pending ? this.$t('search.failed') : this.$t('search.hint')
|
||||||
},
|
},
|
||||||
|
isActive() {
|
||||||
|
return !isEmpty(this.lastSearchTerm)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async query(value) {
|
isFirstOfType(option) {
|
||||||
if (
|
return (
|
||||||
isEmpty(value) ||
|
this.options.findIndex(o => o === option) ===
|
||||||
value.length < 3 ||
|
this.options.findIndex(o => o.__typename === option.__typename)
|
||||||
this.quickValue.toLowerCase() === value.toLowerCase()
|
)
|
||||||
) {
|
|
||||||
this.clear()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.quickValue = value
|
|
||||||
this.pending = true
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: { findResources },
|
|
||||||
} = await this.$apollo.query({
|
|
||||||
query: findResourcesQuery,
|
|
||||||
variables: {
|
|
||||||
query: value,
|
|
||||||
},
|
},
|
||||||
})
|
onFocus(event) {
|
||||||
this.searchResults = findResources
|
|
||||||
} catch (error) {
|
|
||||||
this.searchResults = []
|
|
||||||
} finally {
|
|
||||||
this.pending = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleInput(e) {
|
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
this.value = e.target ? e.target.value.trim() : ''
|
this.isOpen = true
|
||||||
|
},
|
||||||
|
handleInput(event) {
|
||||||
|
clearTimeout(this.searchProcess)
|
||||||
|
this.value = event.target ? event.target.value.trim() : ''
|
||||||
this.isOpen = true
|
this.isOpen = true
|
||||||
this.unprocessedSearchInput = this.value
|
this.unprocessedSearchInput = this.value
|
||||||
|
if (isEmpty(this.value) || this.value.length < 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.searchProcess = setTimeout(() => {
|
this.searchProcess = setTimeout(() => {
|
||||||
this.lastSearchTerm = this.value
|
this.lastSearchTerm = this.value
|
||||||
this.query(this.value)
|
this.$emit('query', this.value)
|
||||||
}, this.delay)
|
}, this.delay)
|
||||||
},
|
},
|
||||||
onSelect(item) {
|
/**
|
||||||
|
* TODO: on enter we should go to a dedicated search page!?
|
||||||
|
*/
|
||||||
|
onEnter(event) {
|
||||||
this.isOpen = false
|
this.isOpen = false
|
||||||
this.$emit('select', item)
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.searchValue = this.lastSearchTerm
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onFocus(e) {
|
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
this.isOpen = true
|
if (!this.pending) {
|
||||||
|
this.lastSearchTerm = this.unprocessedSearchInput
|
||||||
|
this.$emit('query', this.unprocessedSearchInput)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onBlur(e) {
|
onDelete(event) {
|
||||||
|
clearTimeout(this.searchProcess)
|
||||||
|
const value = event.target ? event.target.value.trim() : ''
|
||||||
|
if (isEmpty(value)) {
|
||||||
|
this.clear()
|
||||||
|
} else {
|
||||||
|
this.handleInput(event)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.isOpen = false
|
||||||
|
this.unprocessedSearchInput = ''
|
||||||
|
this.lastSearchTerm = ''
|
||||||
|
this.searchValue = ''
|
||||||
|
this.$emit('clearSearch')
|
||||||
|
clearTimeout(this.searchProcess)
|
||||||
|
},
|
||||||
|
onBlur(event) {
|
||||||
this.searchValue = this.lastSearchTerm
|
this.searchValue = this.lastSearchTerm
|
||||||
// this.$nextTick(() => {
|
// this.$nextTick(() => {
|
||||||
// this.searchValue = this.lastSearchTerm
|
// this.searchValue = this.lastSearchTerm
|
||||||
@ -162,62 +154,59 @@ export default {
|
|||||||
this.isOpen = false
|
this.isOpen = false
|
||||||
clearTimeout(this.searchProcess)
|
clearTimeout(this.searchProcess)
|
||||||
},
|
},
|
||||||
onDelete(e) {
|
onSelect(item) {
|
||||||
clearTimeout(this.searchProcess)
|
|
||||||
const value = e.target ? e.target.value.trim() : ''
|
|
||||||
if (isEmpty(value)) {
|
|
||||||
this.clear()
|
|
||||||
} else {
|
|
||||||
this.handleInput(e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* TODO: on enter we should go to a dedicated search page!?
|
|
||||||
*/
|
|
||||||
onEnter(e) {
|
|
||||||
// this.isOpen = false
|
|
||||||
clearTimeout(this.searchProcess)
|
|
||||||
if (!this.pending) {
|
|
||||||
// this.lastSearchTerm = this.unprocessedSearchInput
|
|
||||||
this.query(this.unprocessedSearchInput)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clear() {
|
|
||||||
this.pending = false
|
|
||||||
this.searchResults = []
|
|
||||||
this.quickValue = ''
|
|
||||||
clearTimeout(this.searchProcess)
|
|
||||||
this.isOpen = false
|
this.isOpen = false
|
||||||
this.unprocessedSearchInput = ''
|
this.goToResource(item)
|
||||||
this.lastSearchTerm = ''
|
this.$nextTick(() => {
|
||||||
this.searchValue = ''
|
this.searchValue = this.lastSearchTerm
|
||||||
|
})
|
||||||
},
|
},
|
||||||
isFirstOfType(option) {
|
goToResource(item) {
|
||||||
return (
|
this.$nextTick(() => {
|
||||||
this.searchResults.findIndex(o => o === option) ===
|
switch (item.__typename) {
|
||||||
this.searchResults.findIndex(o => o.__typename === option.__typename)
|
case 'Post':
|
||||||
)
|
this.$router.push({
|
||||||
|
name: 'post-id-slug',
|
||||||
|
params: { id: item.id, slug: item.slug },
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'User':
|
||||||
|
this.$router.push({
|
||||||
|
name: 'profile-id-slug',
|
||||||
|
params: { id: item.id, slug: item.slug },
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.search {
|
.searchable-input {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
$padding-left: $space-x-small;
|
$padding-left: $space-x-small;
|
||||||
.search-option-label {
|
.search-heading {
|
||||||
align-self: center;
|
display: flex;
|
||||||
padding-left: $padding-left;
|
flex-wrap: wrap;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: default;
|
||||||
|
background-color: white;
|
||||||
|
margin: -8px;
|
||||||
|
padding: 8px;
|
||||||
}
|
}
|
||||||
.search-option-meta {
|
.extra-space {
|
||||||
align-self: center;
|
margin-top: 8px;
|
||||||
.ds-flex {
|
padding-top: 4px;
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
.flex-span {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
&,
|
&,
|
||||||
.ds-select-dropdown {
|
.ds-select-dropdown {
|
||||||
@ -241,15 +230,6 @@ export default {
|
|||||||
width: 36px;
|
width: 36px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.search-meta {
|
|
||||||
float: right;
|
|
||||||
padding-top: 2px;
|
|
||||||
white-space: nowrap;
|
|
||||||
word-wrap: none;
|
|
||||||
.base-icon {
|
|
||||||
vertical-align: sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ds-select {
|
.ds-select {
|
||||||
z-index: $z-index-dropdown + 1;
|
z-index: $z-index-dropdown + 1;
|
||||||
}
|
}
|
||||||
@ -267,16 +247,5 @@ export default {
|
|||||||
.control {
|
.control {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.search-option-heading {
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: default;
|
|
||||||
background-color: white;
|
|
||||||
margin: -8px;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
.extra-space {
|
|
||||||
margin-top: 8px;
|
|
||||||
padding-top: 4px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -21,7 +21,7 @@
|
|||||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||||
>
|
>
|
||||||
<div id="nav-search-box" v-if="isLoggedIn">
|
<div id="nav-search-box" v-if="isLoggedIn">
|
||||||
<search-input id="nav-search" :delay="300" @select="goToResource" />
|
<search-resources />
|
||||||
</div>
|
</div>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||||||
import SearchInput from '~/components/SearchInput/SearchInput.vue'
|
import SearchResources from '~/components/features/SearchResources/SearchResources.vue'
|
||||||
import Modal from '~/components/Modal'
|
import Modal from '~/components/Modal'
|
||||||
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
|
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
|
||||||
import seo from '~/mixins/seo'
|
import seo from '~/mixins/seo'
|
||||||
@ -96,7 +96,7 @@ import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
LocaleSwitch,
|
LocaleSwitch,
|
||||||
SearchInput,
|
SearchResources,
|
||||||
Modal,
|
Modal,
|
||||||
NotificationMenu,
|
NotificationMenu,
|
||||||
AvatarMenu,
|
AvatarMenu,
|
||||||
@ -126,26 +126,6 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goToResource(item) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
switch (item.__typename) {
|
|
||||||
case 'Post':
|
|
||||||
this.$router.push({
|
|
||||||
name: 'post-id-slug',
|
|
||||||
params: { id: item.id, slug: item.slug },
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'User':
|
|
||||||
this.$router.push({
|
|
||||||
name: 'profile-id-slug',
|
|
||||||
params: { id: item.id, slug: item.slug },
|
|
||||||
})
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
toggleMobileMenuView() {
|
toggleMobileMenuView() {
|
||||||
this.toggleMobileMenu = !this.toggleMobileMenu
|
this.toggleMobileMenu = !this.toggleMobileMenu
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user