This commit is contained in:
Vri 🌈 2023-06-28 19:05:46 +02:00
parent dc98b0bf37
commit 073082b520
Signed by: vrifox
GPG key ID: D40098E5B60B2197
13 changed files with 139 additions and 185 deletions

View file

@ -1,26 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Paper, Search, Filter } from '@/types' import { state, fetchPapers, getTopics } from '@/stores'
import { state, papersFetch } from '@/store'
import MainMenu from '@/components/MainMenu.vue' import MainMenu from '@/components/MainMenu.vue'
import SearchBar from '@/components/SearchBar.vue' import SearchBar from '@/components/SearchBar.vue'
import FilterView from './components/papers/FilterView.vue' /* import FooterMenu from '@/components/FooterMenu.vue' */
import FooterMenu from '@/components/FooterMenu.vue'
import { onMounted } from 'vue' import { onMounted } from 'vue'
const applicationName: string = 'Stadtratmonitor' const applicationName: string = 'Stadtratmonitor'
const cityName: string = 'Leipzig' const cityName: string = 'Leipzig'
let search: Search = {
value: '', onMounted (async () => {
type: '', await fetchPapers()
} getTopics()
let filter: Filter = { })
type: {
key: '',
value: '',
},
originator: '',
}
onMounted (() => papersFetch() )
</script> </script>
<template> <template>
@ -34,18 +25,11 @@ onMounted (() => papersFetch() )
</h1> </h1>
<MainMenu /> <MainMenu />
</div> </div>
<SearchBar <SearchBar />
@searchSubmit="(type) => search.type = type"
@searchQuery="(query) => search.value = query"
/>
</header> </header>
<main class="flex flex-row max-w-5xl m-auto"> <main class="flex flex-row max-w-5xl m-auto">
{{ state.topics }} <RouterView>
<RouterView
:search="search"
:filter="filter"
>
</RouterView> </RouterView>
</main> </main>
<footer> <footer>

View file

@ -1,9 +1,12 @@
<script lang="ts"> <script setup lang="ts">
export default { const entries = {
data() { 0: {
return { name: 'Impressum',
menuEntries: this.footerMenuEntries, uri: '/impressum',
} },
1: {
name: 'Über diese Seite',
uri: '/über',
}, },
} }
</script> </script>
@ -11,11 +14,11 @@ export default {
<template> <template>
<ul class="flex flex-row place-content-center"> <ul class="flex flex-row place-content-center">
<li <li
v-for="{entry, i} of menuEntries"
:key="i"
class="p-2 place-content-center" class="p-2 place-content-center"
v-for="{entry, i} of entries"
:key="i"
> >
<a :href="entry.uri">{{ entry.name }}</a> <RouterLink :to="entry.uri">{{ entry.name }}</RouterLink>
</li> </li>
</ul> </ul>
</template> </template>

View file

@ -1,10 +1,17 @@
<script lang="ts"> <script setup lang="ts">
export default { const entries = {
data() { 0: {
return { name: 'Themen',
entries: this.mainMenuEntries uri: '/themen',
} },
} 1: {
name: 'Karte',
uri: '/karte',
},
2: {
name: 'Dokumentation',
uri: '/doku',
},
} }
</script> </script>

View file

@ -1,23 +1,11 @@
<script lang="ts"> <script setup lang="ts">
export default { import { updateSearch } from '@/stores';
updated() { import { onUpdated, ref } from 'vue';
this.$emit('searchQuery', this.search.value)
}, let searchValue = ref('')
data() { let searchType = ref('')
return { function submit(type: string) { searchType = ref(type) }
search: { onUpdated(() => updateSearch(searchValue, searchType))
value: '',
type: '',
},
}
},
methods: {
submit(type: string) {
this.search.type = type
this.$emit('searchSubmit', this.search.type)
}
},
}
</script> </script>
<template> <template>
@ -27,7 +15,7 @@ export default {
class="p-6 grow bg-transparent placeholder:text-text-300 dark:placeholder:text-text-700 text-2xl text-center focus-visible:outline focus-visible:outline-current" class="p-6 grow bg-transparent placeholder:text-text-300 dark:placeholder:text-text-700 text-2xl text-center focus-visible:outline focus-visible:outline-current"
type="search" type="search"
placeholder="z. B. Thema, Name, VII-EF-08640, …" placeholder="z. B. Thema, Name, VII-EF-08640, …"
v-model="search.value" v-model="searchValue"
@keyup.alt.enter.exact="submit('assist')" @keyup.alt.enter.exact="submit('assist')"
@keyup.enter.exact="submit('filter')" @keyup.enter.exact="submit('filter')"
/> />
@ -48,4 +36,5 @@ export default {
</div> </div>
</div> </div>
</form> </form>
{{ searchValue + searchType }}
</template> </template>

View file

@ -1,13 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Paper, Filter } from '@/types' import type { Paper, Filter } from '@/types'
import { state, updateFilter } from '@/stores';
import { computed, onUpdated } from 'vue'; import { computed, onUpdated } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute()
const props = defineProps<{
papers: Array<Paper>,
}>()
const paperTypes = [ const paperTypes = [
{ {
value: 'Anfrage', value: 'Anfrage',
@ -52,13 +47,13 @@ const filter: Filter = {
originator: '', originator: '',
} }
const paperOriginators = computed(() => { const paperOriginators = computed(() => {
return [...new Set(props.papers?.map((paper: Paper) => paper.originator))].sort() return [...new Set(state.papers?.map((paper: Paper) => paper.originator))].sort()
}) })
/* const paperType = computed(() => { /* const paperType = computed(() => {
return paperTypes.filter((type) => type.key == ) return paperTypes.filter((type) => type.key == )
}) */ }) */
onUpdated(() => { onUpdated(() => {
route.$emit('filter', filter) updateFilter(filter.type.key, filter.type.value, filter.originator)
}) })
</script> </script>

View file

@ -1,49 +1,51 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Topic, Search, Filter } from '@/types' import { state } from '@/stores'
import { computed } from 'vue'; import type { Topic } from '@/types';
import { computed, onMounted, onUpdated } from 'vue';
const props = defineProps<{
topics: Array<Topic>,
search: Search,
filter: Filter,
}>()
const filteredData = computed(() => { const filteredData = computed(() => {
//const searchValue: string = search['value']; const searchValue: string = state.search.value;
let filteredTopics = props.topics let filteredTopics = state.topics
/* if (searchValue !== '') { if (state.search.value !== '') {
filteredTopics = this.topics?.filter((topic: Object) => { filteredTopics = state.topics?.filter((topic: Topic) => {
return topic.papers?.filter().name.toLowerCase().includes(searchValue.toLowerCase()) || paper.content.toLowerCase().includes(searchValue.toLowerCase()) || paper.reference.toLowerCase().includes(searchValue.toLowerCase()) return topic.papers?.filter((paper) => {
}) as Array<Object> paper.name.toLowerCase().includes(searchValue.toLowerCase()) /* || paper.content.toLowerCase().includes(searchValue.toLowerCase()) || paper.reference.toLowerCase().includes(searchValue.toLowerCase()) */
} */ })
})
}
/* if (this.filter?.type !== '') { /* if (this.filter?.type !== '') {
filteredTopics = filteredTopics.filter((topic: any) => { filteredTopics = filteredTopics.filter((topic: any) => {
return topic.reference.includes(this.filter?.type.key) && topic.paper_type.includes(this.filter?.type.value) return topic.reference.includes(this.filter?.type.key) && topic.paper_type.includes(this.filter?.type.value)
}) })
} } */
if (this.filter?.originator !== '') { /* if (this.filter?.originator !== '') {
filteredTopics = filteredTopics.filter((topic: any) => { filteredTopics = filteredTopics.filter((topic: any) => {
return topic.originator.includes(this.filter?.originator) return topic.originator.includes(this.filter?.originator)
}) })
} */ } */
return filteredTopics return filteredTopics
}) })
const filteredDataLength = computed(() => { let filteredDataLength: number = 0
if (filteredData.value !== undefined) {
return Object.keys(filteredData).length
} else {
return 0
}
})
function date(paperDate: Date) { function objectLength(data: any) {
return Object.keys(data).length
}
function date(paperDate: string) {
const date = new Date(paperDate) const date = new Date(paperDate)
return new Intl.DateTimeFormat('de-DE', { dateStyle: 'full' }).format(date) return new Intl.DateTimeFormat('de-DE', { dateStyle: 'full' }).format(date)
} }
onMounted(() => {
filteredDataLength = objectLength(filteredData)
})
onUpdated(() => {
filteredDataLength = objectLength(filteredData)
})
</script> </script>
<template> <template>
{{ state.search.value }}
<ul <ul
v-if="filteredDataLength" v-if="filteredDataLength > 0"
class="w-full grid grid-flow-row gap-2 my-2" class="w-full grid grid-flow-row gap-2 my-2"
> >
<p>Wir konnten {{ filteredDataLength }} Einträge finden</p> <p>Wir konnten {{ filteredDataLength }} Einträge finden</p>
@ -55,15 +57,15 @@ function date(paperDate: Date) {
class="p-4 rounded-lg bg-background-100 dark:bg-background-900" class="p-4 rounded-lg bg-background-100 dark:bg-background-900"
> >
<h4 class="text-xl">{{ topic.papers[0].name }}</h4> <h4 class="text-xl">{{ topic.papers[0].name }}</h4>
<!-- <p>{{ date(topic.papers[0].published_at) }}: <a :href="topic.papers[0].url" class="text-secondary-button-500">{{ paper.paper_type}} von {{ paper.originator }}</a></p> --> <p>{{ date(topic.papers[0].published_at) }}: <a :href="topic.papers[0].url" class="text-secondary-button-500">{{ topic.papers[0].paper_type}} von {{ topic.papers[0].originator }}</a></p>
</article> </article>
</li> </li>
</ul> </ul>
<!-- <p <p
class="flex place-content-center my-60 text-lg" class="flex place-content-center my-60 text-lg"
v-else-if="topics?.length" v-else-if="state.topics?.length"
>Für dieses Anfrage liegen uns keine Ergebnisse vor. >Für dieses Anfrage liegen uns keine Ergebnisse vor.
</p> --> </p>
<p <p
class="flex place-content-center my-60 text-lg" class="flex place-content-center my-60 text-lg"
v-else v-else

View file

@ -6,32 +6,4 @@ import router from '@/router'
const app = createApp(App) const app = createApp(App)
app.config.globalProperties = {
...app.config.globalProperties,
mainMenuEntries: {
0: {
name: 'Themen',
uri: '/themen',
},
1: {
name: 'Karte',
uri: '/karte'
},
2: {
name: 'Dokumentation',
uri: '/doku'
}
},
footerMenuEntries: {
0: {
name: 'Impressum',
uri: '/impressum',
},
1: {
name: 'Über diese Seite',
uri: '/über'
},
},
}
app.use(router).mount('#app') app.use(router).mount('#app')

View file

@ -10,7 +10,6 @@ const routes: Array<any> = [
path: '/themen/', path: '/themen/',
name: 'topics', name: 'topics',
component: ()=>import("@/views/TheTopics.vue"), component: ()=>import("@/views/TheTopics.vue"),
props: { topics: true, search: true },
}, { }, {
path: '/themen/:reference', path: '/themen/:reference',
name: 'topics.show', name: 'topics.show',

View file

@ -1,25 +0,0 @@
import { reactive } from 'vue'
import type { Paper, Topic } from '@/types'
const apiUrl: URL = new URL(
'https://raw.githubusercontent.com/CodeforLeipzig/stadtratmonitor/master/input.json'
)
interface State {
papers: Paper[]
topics: Topic[]
}
export const state: State = reactive({ papers: [], topics: [] })
export async function papersFetch() {
const papersData: Paper[] = await (await fetch(apiUrl)).json()
const topicReferences = await [...new Set(papersData?.map((paper) => paper.reference))]
state.papers = papersData
state.topics = await topicReferences.map((reference) => {
return {
reference: reference,
papers: papersData?.filter((paper: Paper) => paper.reference === reference)
}
})
}

49
src/stores/index.ts Normal file
View file

@ -0,0 +1,49 @@
import { reactive, type Ref, ref } from 'vue'
import type { Filter, Paper, Search, Topic } from '@/types'
const apiUrl: URL = new URL('https://raw.githubusercontent.com/CodeforLeipzig/stadtratmonitor/master/input.json')
interface State {
papers: Paper[],
topics: Topic[],
search: Search,
filter: Filter[],
}
export const state: State = reactive({
papers: [],
topics: [],
search: { value: ref(), type: ref() },
filter: [],
})
export async function fetchPapers() {
state.papers = await (await fetch(apiUrl)).json()
}
export function getTopics() {
const topicReferences = [...new Set(state.papers?.map((paper) => paper.reference))]
state.topics = topicReferences.map((reference) => {
return {
reference: reference,
papers: state.papers?.filter((paper: Paper) => paper.reference === reference)
}
})
}
export function updateSearch(searchValue: Ref, searchType: Ref) {
state.search = {
value: searchValue,
type: searchType,
}
}
export function updateFilter(typeKey: string, typeValue: string, originator: string) {
state.filter = [{
type: {
key: typeKey,
value: typeValue,
},
originator: originator,
}]
}

View file

@ -1,3 +1,5 @@
import type { Ref } from "vue";
export interface Topic { export interface Topic {
reference: string, reference: string,
papers: Array<Paper>, papers: Array<Paper>,
@ -16,8 +18,8 @@ export interface Paper {
} }
export interface Search { export interface Search {
value: string, value: Ref,
type: string, type: Ref,
} }
export interface Filter { export interface Filter {

View file

@ -1,31 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Topic, Paper, Search, Filter } from '@/types'
import { papers } from '@/store'
import { computed } from 'vue';
import FilterSidebar from '@/components/papers/FilterSidebar.vue' import FilterSidebar from '@/components/papers/FilterSidebar.vue'
import TopicList from '@/components/papers/TopicList.vue' import TopicList from '@/components/papers/TopicList.vue'
const props = defineProps<{
search: Search,
filter: Filter,
}>()
const topics = computed(() => {
const topicReferences = [...new Set(papers.papers?.map((paper: Paper) => paper.reference))]
return topicReferences.map( (reference: string) => {
return {
'reference': reference,
'papers': papers.papers?.filter( (paper: Paper) => paper.reference === reference),
}
}) as Array<Topic>
})
</script> </script>
<template> <template>
<FilterSidebar <FilterSidebar />
@filter="(filter: Filter) => filter = filter" <TopicList />
/>
<TopicList
:searchProp="search"
:filterProp="filter"
/>
</template> </template>

View file

@ -1,19 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' /* import { computed } from 'vue'
import type { Paper } from '@/types' import type { Paper } from '@/types'
import { useRouter, useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const props = defineProps({ const props = defineProps({
papers: Array<Paper>, papers: Array<Paper>,
}) })
const router = useRouter()
const route = useRoute() const route = useRoute()
const topicId = computed(() => { const topicId = computed(() => {
return route.params.id return route.params.id
}) })
const topic = computed(() => { const topic = computed(() => {
props.papers?.find( (paper: any) => paper.reference == topicId ) return props.papers?.find( (paper: any) => paper.reference == topicId.value )
}) }) */
</script> </script>
<template> <template>