This commit is contained in:
Vri 🌈 2023-06-26 21:41:56 +02:00
parent 92ab1d5d46
commit 71dc064ab6
Signed by: vrifox
GPG key ID: D40098E5B60B2197
18 changed files with 316 additions and 289 deletions

View file

@ -1,63 +1,38 @@
<script lang="ts"> <script setup lang="ts">
import type { Paper, Search, Filter } from '@/types'
import { papers, topics, 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 FilterView from './components/papers/FilterView.vue'
import FooterMenu from '@/components/FooterMenu.vue' import FooterMenu from '@/components/FooterMenu.vue'
import { onMounted } from 'vue'
export type Papers = { const applicationName: string = 'Stadtratmonitor'
body: string const cityName: string = 'Leipzig'
content: string let search: Search = {
name: string
resolution: string
originator: string
paper_type: string
published_at: string
reference: string
url: string
}
export default {
components: {
MainMenu,
SearchBar,
FilterView,
FooterMenu,
},
data() {
return {
applicationName: this.applicationName,
cityName: this.cityName,
search: {
value: '', value: '',
type: '', type: '',
}, }
filter: { let filter: Filter = {
type: { type: {
key: '', key: '',
value: '', value: '',
}, },
originator: '', originator: '',
},
apiUri: 'https://raw.githubusercontent.com/CodeforLeipzig/stadtratmonitor/master/input.json',
papers: [] as Papers[],
}
},
methods: {
async fetchData() {
this.papers = await (await fetch(this.apiUri)).json()
},
},
created() {
this.fetchData()
},
} }
onMounted (() => papersfetch() )
/* onMounted(() => topics.process() ) */
</script> </script>
<template> <template>
<header class="w-screen flex flex-col place-content-center bg-background-100 dark:bg-background-900 text-text-900 dark:text-text-100"> <header class="w-screen flex flex-col place-content-center bg-background-100 dark:bg-background-900 text-text-900 dark:text-text-100">
<div class="flex flex-row place-content-center"> <div class="flex flex-row place-content-center">
<h1 class="p-2 text-xl"> <h1 class="p-2 text-xl">
<RouterLink to="/">{{ applicationName }} {{ cityName }}</RouterLink></h1> <RouterLink
to="/"
>{{ applicationName }} {{ cityName }}
</RouterLink>
</h1>
<MainMenu /> <MainMenu />
</div> </div>
<SearchBar <SearchBar
@ -67,11 +42,12 @@ export default {
</header> </header>
<main class="flex flex-row max-w-5xl m-auto"> <main class="flex flex-row max-w-5xl m-auto">
{{ papers }}
<RouterView <RouterView
:papers="papers"
:search="search" :search="search"
:filter="filter" :filter="filter"
></RouterView> >
</RouterView>
</main> </main>
<footer> <footer>
<!-- <FooterMenu /> --> <!-- <FooterMenu /> -->

View file

@ -0,0 +1,106 @@
<script setup lang="ts">
import type { Paper, Filter } from '@/types'
import { computed, onUpdated } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute()
const props = defineProps<{
papers: Array<Paper>,
}>()
const paperTypes = [
{
value: 'Anfrage',
key: 'F',
}, {
value: 'Einwohneranfrage',
key: 'EF',
}, {
value: 'Antrag',
key: 'A',
}, {
value: 'Antwort zur Anfrage',
key: 'AW',
}, {
value: 'Änderungsantrag',
key: 'ÄA',
}, {
value: 'Beschlussvorlage',
key: 'DS',
}, {
value: 'Informationsvorlage',
key: 'Ifo',
}, {
value: 'Neufassung',
key: 'NF',
}, {
value: 'Petition',
key: 'P',
}, {
value: 'Verwaltungsstandpunkt',
key: 'VSP',
}, {
value: 'Wichtige Angelegenheit',
key: 'WA',
},
]
const filter: Filter = {
type: {
key: '',
value: '',
},
originator: '',
}
const paperOriginators = computed(() => {
return [...new Set(props.papers?.map((paper: Paper) => paper.originator))].sort()
})
/* const paperType = computed(() => {
return paperTypes.filter((type) => type.key == )
}) */
onUpdated(() => {
route.$emit('filter', filter)
})
</script>
<template>
<form class="mr-4 mt-4">
<fieldset class="flex flex-row mb-4">
<legend>Kategorie</legend>
<select
class="w-40 p-2 bg-background-100 dark:bg-background-900 rounded-lg"
v-model="filter.type"
>
<option
v-for="(type, i) of paperTypes"
:key="i"
:value="type"
>{{ type.value }}
</option>
</select>
<button
class="pl-2"
@click.prevent="filter.type = { key: '', value: ''}"
title="zurücksetzen"
>
</button>
</fieldset>
<fieldset class="flex flex-row mb-4">
<legend>Einreicher</legend>
<select
class="w-40 p-2 bg-background-100 dark:bg-background-900 rounded-lg"
v-model="filter.originator">
<option
v-for="(originator, i) of paperOriginators"
:key="i"
>{{ originator }}
</option>
</select>
<button
class="pl-2"
@click.prevent="filter.originator = ''"
title="zurücksetzen"
>
</button>
</fieldset>
</form>
</template>

View file

@ -1,116 +0,0 @@
<script lang="ts">
export default {
updated() {
this.$emit('filter', this.filter)
},
data() {
return {
paperTypes: [
{
value: 'Anfrage',
key: 'F',
},
{
value: 'Einwohneranfrage',
key: 'EF',
},
{
value: 'Antrag',
key: 'A',
},
{
value: 'Antwort zur Anfrage',
key: 'AW',
},
{
value: 'Änderungsantrag',
key: 'ÄA',
},
{
value: 'Beschlussvorlage',
key: 'DS',
},
{
value: 'Informationsvorlage',
key: 'Ifo',
},
{
value: 'Neufassung',
key: 'NF',
},
{
value: 'Petition',
key: 'P',
},
{
value: 'Verwaltungsstandpunkt',
key: 'VSP',
},
{
value: 'Wichtige Angelegenheit',
key: 'WA',
},
],
filter: {
type: {
key: '',
value: '',
},
originator: '',
},
}
},
props: {
papers: Array<any>,
},
computed: {
paperOriginators() {
return [...new Set(this.papers?.map((paper: any) => paper.originator))].sort()
},
/* paperType() {
return this.paperTypes.filter((type) => type.key == )
}, */
},
methods: {
}
}
</script>
<template>
<form class="mr-4 mt-4">
<fieldset class="flex flex-row mb-4">
<legend>Kategorie</legend>
<select
class="w-40 p-2 bg-background-100 dark:bg-background-900 rounded-lg"
v-model="filter.type">
<option
v-for="(type, i) of paperTypes"
:key="i"
:value="type"
>{{ type.value }}
</option>
</select>
<button
class="pl-2"
@click.prevent="filter.type = { key: '', value: ''}"
title="zurücksetzen"
>
</button>
</fieldset>
<fieldset class="flex flex-row mb-4">
<legend>Einreicher</legend>
<select
class="w-40 p-2 bg-background-100 dark:bg-background-900 rounded-lg"
v-model="filter.originator">
<option v-for="(originator, i) of paperOriginators" :key="i">{{ originator }}</option>
</select>
<button
class="pl-2"
@click.prevent="filter.originator = ''"
title="zurücksetzen"
>
</button>
</fieldset>
</form>
</template>

View file

@ -1,8 +1,6 @@
<script lang="ts"> <script setup lang="ts">
export default {
}
</script> </script>
<template> <template>
<div></div> Paper
</template> </template>

View file

@ -1,19 +1,18 @@
<script lang="ts"> <script setup lang="ts">
import { type Papers } from '@/App.vue' import type { Topic, Search, Filter } from '@/types'
import { computed } from 'vue';
export default { const props = defineProps<{
props: { topics: Array<Topic>,
search: Object, search: Search,
filter: Object, filter: Filter,
topics: Array<Object>, }>()
}, const filteredData = computed(() => {
computed: { //const searchValue: string = search['value'];
filteredData(): Array<Object> { let filteredTopics = props.topics
const paperQuery: String = this.search?.value /* if (searchValue !== '') {
let filteredTopics: Array<Object> = this.topics as Array<Object>
/* if (paperQuery !== '') {
filteredTopics = this.topics?.filter((topic: Object) => { filteredTopics = this.topics?.filter((topic: Object) => {
return topic.papers?.filter().name.toLowerCase().includes(paperQuery.toLowerCase()) || paper.content.toLowerCase().includes(paperQuery.toLowerCase()) || paper.reference.toLowerCase().includes(paperQuery.toLowerCase()) return topic.papers?.filter().name.toLowerCase().includes(searchValue.toLowerCase()) || paper.content.toLowerCase().includes(searchValue.toLowerCase()) || paper.reference.toLowerCase().includes(searchValue.toLowerCase())
}) as Array<Object> }) as Array<Object>
} */ } */
/* if (this.filter?.type !== '') { /* if (this.filter?.type !== '') {
@ -27,41 +26,36 @@ export default {
}) })
} */ } */
return filteredTopics return filteredTopics
}, })
}, const filteredDataLength = computed(() => {
methods: { if (filteredData.value !== undefined) {
openPaper() { return Object.keys(filteredData).length
} else {
return 0
}
})
}, function date(paperDate: Date) {
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)
},
filteredDataLength(): Number {
return Object.keys(this.filteredData).length
},
},
} }
</script> </script>
<template> <template>
{{ topics }}
<ul <ul
v-if="filteredDataLength" v-if="filteredDataLength"
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>
{{ filteredData }}
<li <li
v-for="(topic, i) in filteredData" v-for="(topic, i) in filteredData"
:key="i" :key="i"
> >
<article <article
class="p-4 rounded-lg bg-background-100 dark:bg-background-900" class="p-4 rounded-lg bg-background-100 dark:bg-background-900"
@click.prevent="openPaper()"
> >
<h4 class="text-xl">{{ topic }}</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">{{ paper.paper_type}} von {{ paper.originator }}</a></p> -->
</article> </article>
</li> </li>
</ul> </ul>

View file

@ -8,9 +8,6 @@ const app = createApp(App)
app.config.globalProperties = { app.config.globalProperties = {
...app.config.globalProperties, ...app.config.globalProperties,
apiUri: 'https://joergreichert.de/srm/input.json',
applicationName: 'Stadtratmonitor',
cityName: 'Leipzig',
mainMenuEntries: { mainMenuEntries: {
0: { 0: {
name: 'Themen', name: 'Themen',

View file

@ -2,16 +2,28 @@ import { createRouter, createWebHistory } from 'vue-router'
import Landing from '@/views/TheLanding.vue' import Landing from '@/views/TheLanding.vue'
const routes: Array<any> = [ const routes: Array<any> = [
{ path: '/', name: 'landing', component: Landing },
{ {
path: '/',
name: 'landing',
component: Landing
}, {
path: '/themen/', path: '/themen/',
name: 'topics', name: 'topics',
component: ()=>import("@/views/TheTopics.vue"), component: ()=>import("@/views/TheTopics.vue"),
props: { topics: true }, props: { topics: true, search: true },
}, {
path: '/themen/:reference',
name: 'topics.show',
component: ()=>import("@/views/TopicsShow.vue")
}, {
path: '/karte',
name: 'map',
component: ()=>import("@/views/TheMap.vue")
}, {
path: '/doku',
name: 'documentation',
component: ()=>import("@/views/TheDocumentation.vue")
}, },
{ path: '/themen/:reference', name: 'topics.show', component: ()=>import("@/views/TopicsShow.vue") },
{ path: '/karte', name: 'map', component: ()=>import("@/views/TheMap.vue") },
{ path: '/doku', name: 'documentation', component: ()=>import("@/views/TheDocumentation.vue") },
] ]
const router: any = createRouter({ const router: any = createRouter({

34
src/store/index.ts Normal file
View file

@ -0,0 +1,34 @@
import { reactive, ref } from 'vue'
import type { Paper, Topic } from '@/types'
const apiUrl: URL = new URL('https://raw.githubusercontent.com/CodeforLeipzig/stadtratmonitor/master/input.json')
export let papers: Array<Paper> = reactive([])
export let topics: Array<Topic> = reactive([])
export async function papersfetch() {
papers = await (await fetch(apiUrl)).json()
/* const topicReferences = await [...new Set(papers?.map((paper: Paper) => paper.reference))]
topics = await topicReferences.map( (reference: string) => {
return {
'reference': reference,
'papers': papers?.filter( (paper: Paper) => paper.reference === reference),
}
}) */
}
/* export function paperprocess() */
/* export const test = reactive({
testi: papers.papers,
funk() {
return [...new Set(papers.papers?.map((paper: Paper) => paper.reference))]
}
}) */
/* export const = reactive({
topics: Array<Topic>,
topicReferences: Set<String>,
async process() {
},
}) */

29
src/types.ts Normal file
View file

@ -0,0 +1,29 @@
export interface Topic {
reference: string,
papers: Array<Paper>,
}
export interface Paper {
body: string,
content: string,
name: string,
resolution: any,
originator: string,
paper_type: string,
published_at: string,
reference: string,
url: string,
}
export interface Search {
value: string,
type: string,
}
export interface Filter {
type: {
key: string,
value: string,
},
originator: string,
}

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script setup lang="ts">
export default {}
</script> </script>
<template> <template>

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script setup lang="ts">
export default {}
</script> </script>
<template> <template>

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script setup lang="ts">
export default {}
</script> </script>
<template> <template>

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script setup lang="ts">
export default {}
</script> </script>
<template> <template>

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script setup lang="ts">
export default {}
</script> </script>
<template> <template>

View file

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

View file

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

View file

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}

View file

@ -7,6 +7,6 @@
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "./src/*" ] "@/*": [ "./src/*" ]
} },
} }
} }