1
0
Fork 0

Use Pinia Colada for organizations.

This commit is contained in:
Brian D 2024-12-08 16:21:39 -05:00
parent f5195e8a48
commit 6b07b56d87
5 changed files with 132 additions and 3 deletions

9
package-lock.json generated
View file

@ -8,6 +8,7 @@
"name": "designer",
"version": "0.0.0",
"dependencies": {
"@pinia/colada": "^0.13.0",
"@primevue/forms": "^4.2.2",
"@primevue/themes": "^4.2.2",
"pinia": "^2.2.6",
@ -1217,6 +1218,14 @@
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
"dev": true
},
"node_modules/@pinia/colada": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@pinia/colada/-/colada-0.13.0.tgz",
"integrity": "sha512-Ah6uv1spRCu3I0QmimOMwrkKMcQK1+Ov2Qroz4PFD2/i9gwRUddj7Pz9kNcg5xXp2WWEPmnvkhTr2GgdqTUaUQ==",
"funding": {
"url": "https://github.com/sponsors/posva"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",

View file

@ -15,6 +15,7 @@
"format": "prettier --write src/"
},
"dependencies": {
"@pinia/colada": "^0.13.0",
"@primevue/forms": "^4.2.2",
"@primevue/themes": "^4.2.2",
"pinia": "^2.2.6",

View file

@ -2,6 +2,7 @@ import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { PiniaColada } from '@pinia/colada';
import App from './App.vue'
import router from './router'
@ -12,6 +13,7 @@ import StyleClass from 'primevue/styleclass';
const app = createApp(App)
app.use(createPinia())
app.use(PiniaColada)
app.use(router)
app.use(PrimeVue, {
theme: {

View file

@ -0,0 +1,22 @@
import { defineQuery, useQuery } from '@pinia/colada'
import { ref } from 'vue'
export interface Organization {
abbrev: string,
id: string,
logo: string,
name: string,
}
export const useOrganization = defineQuery(() => {
const search = ref('')
const { state, ...rest } = useQuery({
key: ['organization'],
query: () => fetch('/api/organization').then((res) => res.json()),
})
return {
...rest,
state,
search,
}
});

View file

@ -1,10 +1,12 @@
<script setup lang="ts">
import { ref, toRaw, watch } from 'vue'
import { computed, ref, toRaw, watch } from 'vue'
import Button from 'primevue/button';
import Card from 'primevue/card';
import Chip from 'primevue/chip';
import ColorPicker from 'primevue/colorpicker';
import { Form } from '@primevue/forms';
import Image from 'primevue/image';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
import InputText from 'primevue/inputtext';
@ -15,12 +17,16 @@ import IconLayout2Vue from '@/components/layouts/IconLayout2.vue';
import IconLayout3Vue from '@/components/layouts/IconLayout3.vue';
import IconLayout4Vue from '@/components/layouts/IconLayout4.vue';
import Sticker from '@/components/Sticker.vue';
import { useSticker } from '@/composables/sticker'
import { activist, type Sticker as StickerType } from '@/stores/stickersStore'
import { type Organization, useOrganization } from '@/queries/organization';
import { useSticker } from '@/composables/sticker';
import { activist, type Sticker as StickerType } from '@/stores/stickersStore';
const { state: orgs } = useOrganization();
const myOrgs = ref<Organization[]>([]);
const original = useSticker();
let sticker = ref<StickerType>(activist);
const orgFilter = ref("");
// When the original sticker appears, copy it into a local coy.
watch(original, (newValue) => {
@ -35,6 +41,22 @@ const resolver = () => {
function onFormSubmit() {
original.value = sticker.value;
}
function addOrg(id: string) {
myOrgs.value.push(orgs.value.data.find((org: Organization) => org.id === id));
}
function removeOrg(orgId: string) {
const myIds = myOrgs.value.map(org => org.id);
let start = myIds.indexOf(orgId);
myOrgs.value.splice(start, 1);
}
const orgOptions = computed(() => {
const myIds = myOrgs.value.map(org => org.id);
return orgs.value.data.filter(({ id, name }) => {
return !myIds.includes(id)
&& name.toLowerCase().includes(orgFilter.value.toLowerCase());
});
});
</script>
<template>
@ -52,6 +74,44 @@ function onFormSubmit() {
@submit="onFormSubmit">
<div class="bg-surface-50 dark:bg-surface-950 px-3 py-5 md:px-12">
<div class="grid grid-cols-12 gap-4">
<div class="col-span-12 flex flex-col gap-4">
<label for="nickname2">Organizations I Support</label>
<div class="my-orgs">
<div v-for="org in myOrgs" :key="org.id">
<Chip
:image="org.logo"
:label="org.abbrev"
removable
v-on:remove="removeOrg(org.id)"
>
</Chip>
</div>
</div>
<InputText
id="nickname2"
type="text"
class="w-full"
placeholder="search"
v-model="orgFilter"
/>
<div v-if="orgs.status === 'pending'">
loading
</div>
<div v-if="orgs.error">
There was an error loading organization data.
</div>
<div class="logos" v-else-if="orgs.data">
<div v-for="org in orgOptions" :key="org.id">
<a @click="addOrg(org.id)">
<Image class="logo" :src="org.logo" alt="Image" />
{{ org.name }}
</a>
</div>
</div>
</div>
<div class="divider" />
<div class="col-span-12">
<label for="nickname2">Layout {{sticker.layout}}</label>
<div class="flex flex-wrap gap-4">
@ -160,4 +220,39 @@ label {
width: 400px;
}
}
.logos {
display: flex;
gap: 1em;
height: 200px;
overflow: auto;
flex-wrap: wrap;
> div {
background-color: #F8F8F8;
border: 1px solid #bbb;
border-radius: 4px;
height: 60px;
padding: 6px;
width: 310px;
> a {
align-items: center;
cursor: pointer;
display: flex;
gap: 1em;
.logo {
filter: grayscale(1);
width: 50px;
}
}
}
}
.my-orgs {
display: flex;
gap: 1em;
font-size: 80%;
.logo {
display: block;
filter: grayscale(1);
width: 50px;
}
}
</style>