Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nav): search by subtheme #168

Merged
merged 21 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions configs/ecospheres/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ website:
logo_operator:
homepage_title: 'Ecosphères'
homepage_subtitle: 'Explorez les données ouvertes et restreintes de la **Transition écologique**, de la **Cohésion des territoires**, de la **Transition énergétique** et de la **Mer**'
search_bar:
search_bar:
display: true
placeholder: 'Rechercher un jeu de données'
secondary_search:
secondary_search:
display: false
name:
link:
Expand Down
6 changes: 3 additions & 3 deletions configs/meteo-france/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ website:
logo_operator: 'https://static.data.gouv.fr/avatars/81/6374003e904fad9ddac7436315fd15-100.png'
homepage_title: 'La météo et le climat en Open Data'
homepage_subtitle: 'meteo.data.gouv.fr centralise et structure les données publiques relatives à la météo et au climat.<br />Vous y trouverez des données brutes téléchargeables et utilisable de manière libre et gratuite.'
search_bar:
search_bar:
display: true
placeholder: 'Rechercher un jeu de données'
secondary_search:
secondary_search:
display: true
name: 'Recherche guidée'
link: '/form'
Expand Down Expand Up @@ -74,7 +74,7 @@ website:
# display settings
pagination_sizes:
organizations_list: 9
topics_list: 100
topics_list: 100
home_banner_colors:
- '#F7EED4'
- '#ECEEE6'
Expand Down
21 changes: 17 additions & 4 deletions src/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,26 @@
align-items: center;
}

.theme_without_breadcrumb {
.without_breadcrumb {
margin: 128px 0 0;
}

.theme_with_breadcrumb {
.with_breadcrumb {
margin: 60px 0 0;
.home-selection-breadcrumb {
text-align: left;
}

.breadcrumb {
margin-top: 40px;
text-align: left;
}

.actionTile {
background: #000092;
.fr-tile__link {
color: white;
}
}

.dsfr_alert {
margin: 20px 0;
}
edelagnier marked this conversation as resolved.
Show resolved Hide resolved
34 changes: 18 additions & 16 deletions src/components/HomeThemes.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="selectedTheme === null" className="theme_without_breadcrumb">
<div className="without_breadcrumb" v-if="selectedTheme === null">
<ul class="fr-grid-row fr-grid-row--gutters es__tiles__list fr-mt-1w">
<li v-for="theme in themeList" class="fr-col-12 fr-col-lg-4">
<Tile
Expand All @@ -11,20 +11,22 @@
</li>
</ul>
</div>
<div v-else className="theme_with_breadcrumb">
<DsfrBreadcrumb class="home-selection-breadcrumb" :links="breadcrumbList" />
<ul class="fr-grid-row fr-grid-row--gutters es__tiles__list fr-mt-1w">
<li
v-for="subtheme in selectedTheme.subthemes"
class="fr-col-12 fr-col-lg-4"
>
<Tile
:style="getCustomBoxShadow(selectedTheme.color)"
:link="goToTopicList(subtheme)"
:title="subtheme.name"
/>
</li>
</ul>
<div v-else>
<DsfrBreadcrumb class="breadcrumb" :links="breadcrumbList" />
<div class="with_breadcrumb">
<ul class="fr-grid-row fr-grid-row--gutters es__tiles__list fr-mt-1w">
<li
v-for="subtheme in selectedTheme.subthemes"
class="fr-col-12 fr-col-lg-4"
>
<Tile
:style="getCustomBoxShadow(selectedTheme.color)"
:link="goToTopicList(subtheme)"
:title="subtheme.name"
/>
</li>
</ul>
</div>
</div>
</template>

Expand Down Expand Up @@ -64,7 +66,7 @@ export default {
return `box-shadow: rgb(221, 221, 221) 0px 0px 0px 1px inset, #${color} 0px -4px 0px 0px inset`
},
goToTopicList(subtheme: Subtheme): string {
return 'link to topic list' // TO DO redirect to search result once the page is created
return `/bouquets/?theme=${this.selectedTheme.name}&subtheme=${subtheme.name}`
},
getThemeDescription(theme: Theme): string {
const nbSubthemes = theme.subthemes.length
Expand Down
123 changes: 123 additions & 0 deletions src/components/TopicList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<template>
<div v-if="bouquets.length > 0">
<p>{{ numberOfResultMsg }}</p>
<div class="fr-grid-row fr-mb-1w">
<DsfrButton
class="fr-mb-1w"
label="Ajouter un bouquet"
icon="ri-add-circle-line"
@click="goToCreate"
/>
</div>
</div>
<div
v-if="bouquets.length === 0"
class="fr-alert fr-alert--info"
data-fr-js-alert-actionee="true"
>
<h3 class="fr-alert__title">Il n'y a pas encore de bouquet sur ce thème</h3>
<p>
N'hésitez pas à contribuer en
<a href="/admin/bouquets/add" target="_blank">en créant un</a>
</p>
</div>
<div class="fr-container--fluid fr-mt-4w fr-mb-4w">
<ul class="fr-grid-row fr-grid-row--gutters es__tiles__list fr-mt-1w">
<li v-for="bouquet in bouquets" class="fr-col-12 fr-col-lg-6">
<Tile
:link="`/bouquets/${bouquet.slug}`"
:title="bouquet.name"
:description="bouquet.description"
:is-markdown="true"
/>
</li>
</ul>
</div>
</template>

<script lang="ts">
import { onMounted } from 'vue'
import { useLoading } from 'vue-loading-overlay'

import type { Topic } from '../model'
import { NoOptionSelected } from '../model'
import { useTopicStore } from '../store/TopicStore'
import Tile from './Tile.vue'

export default {
name: 'TopicList',
components: {
Tile: Tile
},
setup() {
onMounted(() => {
const loader = useLoading().show()
useTopicStore()
.loadTopicsForUniverse()
.finally(() => {
loader.hide()
})
})
},
props: {
themeName: {
type: String,
default: NoOptionSelected
},
subthemeName: {
type: String,
default: NoOptionSelected
}
},
computed: {
bouquets(): Topic[] {
const allTopics = useTopicStore().$state.data
if (this.themeName === NoOptionSelected) {
return allTopics
}
const relevantTopics: Topic[] = []
if (this.subthemeName !== NoOptionSelected) {
for (const topic of allTopics) {
if (
this.isRelevant(topic, 'subtheme', this.subthemeName) &&
this.isRelevant(topic, 'theme', this.themeName)
) {
relevantTopics.push(topic)
}
}
} else if (this.themeName !== NoOptionSelected) {
for (const topic of allTopics) {
if (this.isRelevant(topic, 'theme', this.themeName)) {
relevantTopics.push(topic)
}
}
}
return relevantTopics
},
numberOfResultMsg(): string {
if (this.bouquets.length === 1) {
return '1 bouquet disponible'
} else {
return this.bouquets.length + ' bouquets disponibles'
}
}
},
methods: {
isRelevant(topic: Topic, property: string, value): Boolean {
const topicInformations: { subtheme: string; theme: string }[] =
topic.extras['ecospheres:informations']
if (topicInformations) {
for (const information of topicInformations) {
if (information[property] === value) {
return true
}
}
}
return false
},
goToCreate() {
this.$router.push({ name: 'bouquet_add' })
}
}
}
</script>
124 changes: 124 additions & 0 deletions src/components/TopicSearch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<template>
<div className="filterForm">
<div class="fr-select-group">
<label class="fr-label" for="select_theme"> Thématiques </label>
<select class="fr-select" id="select_theme" @change="switchTheme($event)">
<option
:value="this.NoOptionSelected"
:selected="themeName == this.NoOptionSelected"
>
Choisir une thématique
</option>
<option
v-for="option in themeOptions"
:value="option.value"
:selected="option.value === themeName"
>
{{ option.text }}
</option>
</select>
</div>

<div class="fr-select-group">
<label class="fr-label" for="select_subtheme"> Chantiers </label>
<select
class="fr-select"
id="select_subtheme"
@change="switchSubtheme($event)"
>
<option
:value="this.NoOptionSelected"
:selected="subthemeName == this.NoOptionSelected"
>
Choisir un chantier
</option>
<option
v-for="option in subthemeOptions"
v-bind:value="option.value"
:selected="option.value === subthemeName"
>
{{ option.text }}
</option>
</select>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

import type { SelectOption } from '@/model'

import config from '../config'
import { NoOptionSelected } from '../model'
import Tile from './Tile.vue'

export default defineComponent({
name: 'TopicSearch',
components: {
Tile: Tile
},
created() {
this.NoOptionSelected = NoOptionSelected
},
props: {
themeName: {
type: String,
default: NoOptionSelected
},
subthemeName: {
type: String,
default: NoOptionSelected
}
},
computed: {
selectedTheme() {
for (const theme of this.themeList) {
if (theme.name === this.themeName) {
return theme
}
}
return null
},
themeList() {
return config.themes
},
themeOptions(): SelectOption[] {
const options: SelectOption[] = []
for (const theme of this.themeList) {
options.push({
value: theme.name,
text: theme.name
})
}
return options
},
subthemeOptions(): SelectOption[] {
const options: SelectOption[] = []
if (this.selectedTheme) {
for (const subtheme of this.selectedTheme.subthemes) {
options.push({
value: subtheme.name,
text: subtheme.name
})
}
}
return options
}
},
methods: {
switchTheme(event) {
this.$router.push({
path: '/bouquets',
query: { theme: event.target.value, subtheme: NoOptionSelected }
})
},
switchSubtheme(event) {
this.$router.push({
path: '/bouquets',
query: { theme: this.themeName, subtheme: event.target.value }
})
}
}
})
</script>
Loading