1<template>
2 <div class="marketplace">
3 <div v-if="loading" class="loading">Loading plugins...</div>
4 <div v-if="error" class="error">Error: {{ error }}</div>
5 <div v-if="!loading && !error" class="grid">
6 <PluginCard v-for="plugin in plugins" :key="plugin.name" :plugin="plugin" />
7 </div>
8 </div>
9</template>
10
11<script setup>
12import { ref, onMounted } from "vue";
13import PluginCard from "./PluginCard.vue";
14
15const REGISTRY_URL =
16 "https://raw.githubusercontent.com/floatpane/matcha/master/plugins/registry.json";
17
18const plugins = ref([]);
19const loading = ref(true);
20const error = ref(null);
21
22onMounted(() => {
23 fetch(REGISTRY_URL)
24 .then((res) => {
25 if (!res.ok) throw new Error(`Failed to fetch registry (${res.status})`);
26 return res.json();
27 })
28 .then((data) => {
29 plugins.value = data;
30 loading.value = false;
31 })
32 .catch((err) => {
33 error.value = err.message;
34 loading.value = false;
35 });
36});
37</script>
38
39<style scoped>
40.marketplace {
41 max-width: 1200px;
42 margin: 0 auto;
43 padding: 0 1rem 3rem;
44}
45
46.grid {
47 display: grid;
48 grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
49 gap: 1.25rem;
50}
51
52.loading,
53.error {
54 text-align: center;
55 color: var(--muted);
56 padding: 3rem 0;
57 font-size: 1.1rem;
58}
59
60.error {
61 color: var(--danger);
62}
63</style>