Skip to content

Commit 5b31c33

Browse files
committed
Initial Making of the Event json manager
1 parent 9cbf833 commit 5b31c33

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed

src/pages/tools/EventMaker.vue

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
<template>
2+
<div class="min-h-screen bg-gray-900 text-white">
3+
<div class="max-w-4xl mx-auto p-6">
4+
<h1 class="text-2xl font-bold mb-4">Event JSON Editor</h1>
5+
<div class="mb-4 flex flex-wrap gap-2 items-center">
6+
<label class="font-semibold">Select year:</label>
7+
<select v-model="selectedFile" @change="loadJson" class="border rounded px-2 py-1">
8+
<option v-for="file in jsonFiles" :key="file" :value="file">{{ file }}</option>
9+
</select>
10+
<button
11+
@click="createNewJson"
12+
class="ml-4 px-3 py-1 bg-green-600 text-white rounded cursor-pointer"
13+
>
14+
New JSON
15+
</button>
16+
<button
17+
@click="downloadJson"
18+
class="ml-2 px-3 py-1 bg-blue-600 text-white rounded cursor-pointer"
19+
:disabled="!jsonData"
20+
>
21+
Download
22+
</button>
23+
</div>
24+
25+
<div v-if="jsonData">
26+
<form @submit.prevent>
27+
<div class="mb-2">
28+
<label class="block font-semibold">Title</label>
29+
<input v-model="jsonData.title" class="border rounded px-2 py-1 w-full" />
30+
</div>
31+
<div class="mb-2">
32+
<label class="block font-semibold">Location</label>
33+
<input v-model="jsonData.location" class="border rounded px-2 py-1 w-full" />
34+
</div>
35+
<div class="mb-2 flex gap-2">
36+
<div>
37+
<label class="block font-semibold">Start</label>
38+
<input
39+
v-model.number="jsonData.start"
40+
type="number"
41+
class="border rounded px-2 py-1 w-20"
42+
/>
43+
</div>
44+
<div>
45+
<label class="block font-semibold">End</label>
46+
<input
47+
v-model.number="jsonData.end"
48+
type="number"
49+
class="border rounded px-2 py-1 w-20"
50+
/>
51+
</div>
52+
<div>
53+
<label class="block font-semibold">Month</label>
54+
<input v-model="jsonData.month" class="border rounded px-2 py-1 w-24" />
55+
</div>
56+
<div>
57+
<label class="block font-semibold">Year</label>
58+
<input
59+
v-model.number="jsonData.year"
60+
type="number"
61+
class="border rounded px-2 py-1 w-24"
62+
/>
63+
</div>
64+
</div>
65+
<div class="mb-2">
66+
<label class="block font-semibold">Live</label>
67+
<input v-model="jsonData.live" class="border rounded px-2 py-1 w-full" />
68+
</div>
69+
<div class="mb-2">
70+
<label class="block font-semibold">Video</label>
71+
<input v-model="jsonData.video" class="border rounded px-2 py-1 w-full" />
72+
</div>
73+
<div class="mb-4">
74+
<label class="block font-semibold">Days & Events</label>
75+
<div v-for="(day, dIdx) in jsonData.days" :key="dIdx" class="border rounded p-2 mb-2">
76+
<div class="flex flex-col md:flex-row gap-2 mb-1">
77+
<input
78+
v-model="day.day"
79+
class="border rounded px-2 py-1 w-full md:w-40"
80+
placeholder="Day"
81+
/>
82+
<input
83+
v-model="day.description"
84+
class="border rounded px-2 py-1 w-full md:w-60"
85+
placeholder="Description"
86+
/>
87+
<button
88+
@click.prevent="removeDay(dIdx)"
89+
class="text-red-600 cursor-pointer md:ml-2"
90+
>
91+
Remove Day
92+
</button>
93+
</div>
94+
<div class="ml-0 md:ml-4">
95+
<div
96+
v-for="(event, eIdx) in day.events"
97+
:key="eIdx"
98+
class="mb-4 p-4 rounded bg-gray-700 flex flex-col md:grid md:grid-cols-2 gap-4"
99+
>
100+
<div class="flex flex-col gap-2">
101+
<input
102+
v-model="event.name"
103+
class="border rounded px-2 py-1 w-full"
104+
placeholder="Event Name"
105+
/>
106+
<input
107+
v-model="event.by"
108+
class="border rounded px-2 py-1 w-full"
109+
placeholder="By"
110+
/>
111+
<input
112+
v-model="event.time"
113+
class="border rounded px-2 py-1 w-full"
114+
placeholder="Time"
115+
/>
116+
<input
117+
v-model="event.place.id"
118+
class="border rounded px-2 py-1 w-full"
119+
placeholder="Place ID"
120+
/>
121+
<input
122+
v-model="event.place.map"
123+
class="border rounded px-2 py-1 w-full"
124+
placeholder="Map"
125+
/>
126+
</div>
127+
<div class="flex flex-col gap-2 h-full">
128+
<label class="font-semibold">Description</label>
129+
<textarea
130+
v-model="event.description"
131+
class="border rounded px-2 py-1 w-full min-h-20 resize-y"
132+
placeholder="Description"
133+
></textarea>
134+
<button
135+
@click.prevent="removeEvent(dIdx, eIdx)"
136+
class="text-red-600 cursor-pointer mt-2 self-end"
137+
>
138+
Remove
139+
</button>
140+
</div>
141+
</div>
142+
<button @click.prevent="addEvent(dIdx)" class="text-green-600 cursor-pointer mt-2">
143+
+ Add Event
144+
</button>
145+
</div>
146+
</div>
147+
<button @click.prevent="addDay" class="text-green-600 cursor-pointer mt-2">
148+
+ Add Day
149+
</button>
150+
</div>
151+
</form>
152+
</div>
153+
<div v-else class="text-gray-500">Select a file or create a new one to begin.</div>
154+
</div>
155+
</div>
156+
</template>
157+
158+
<script setup>
159+
import { ref } from "vue"
160+
161+
const jsonFiles = ["2014.json", "2015.json", "2016.json", "2017.json"]
162+
const selectedFile = ref("2014.json")
163+
const jsonData = ref(null)
164+
165+
async function loadJson() {
166+
// Use dynamic import for local JSON files
167+
const year = selectedFile.value.replace(".json", "")
168+
try {
169+
const module = await import(`@/data/${year}.json`)
170+
jsonData.value = module.default
171+
} catch (e) {
172+
jsonData.value = null
173+
console.error("Failed to load JSON:", e)
174+
}
175+
}
176+
177+
function createNewJson() {
178+
jsonData.value = {
179+
title: "",
180+
location: "",
181+
start: 1,
182+
end: 1,
183+
month: "",
184+
year: new Date().getFullYear(),
185+
live: "",
186+
archive: false,
187+
video: "",
188+
days: [],
189+
}
190+
selectedFile.value = ""
191+
}
192+
193+
function addDay() {
194+
jsonData.value.days.push({ day: "", description: "", events: [] })
195+
}
196+
function removeDay(idx) {
197+
jsonData.value.days.splice(idx, 1)
198+
}
199+
function addEvent(dayIdx) {
200+
jsonData.value.days[dayIdx].events.push({
201+
name: "",
202+
by: "",
203+
time: "",
204+
place: { id: "", map: "" },
205+
description: "",
206+
})
207+
}
208+
function removeEvent(dayIdx, eventIdx) {
209+
jsonData.value.days[dayIdx].events.splice(eventIdx, 1)
210+
}
211+
212+
function downloadJson() {
213+
const blob = new Blob([JSON.stringify(jsonData.value, null, 2)], { type: "application/json" })
214+
const url = URL.createObjectURL(blob)
215+
const a = document.createElement("a")
216+
a.href = url
217+
a.download = selectedFile.value || "new-event.json"
218+
a.click()
219+
URL.revokeObjectURL(url)
220+
}
221+
222+
// Auto-load first file
223+
if (!jsonData.value) loadJson()
224+
</script>
225+
226+
<style scoped>
227+
/* Add your styles here */
228+
</style>

src/router/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from "vue-router"
22
import LiveSite from "../pages/LiveSite.vue"
33
import ComingSoonPage from "../pages/ComingSoonPage.vue"
44
import CallForTalks from "../pages/CallForTalks.vue"
5+
import eventMaker from "../pages/tools/EventMaker.vue"
56

67
const isDevEnabled = import.meta.env.VITE_DEV === "true"
78

@@ -10,6 +11,7 @@ const routes = [
1011
{ path: "/cft", component: CallForTalks },
1112
{ path: "/soon", component: ComingSoonPage },
1213
{ path: "/:pathMatch(.*)*", component: LiveSite },
14+
{ path: "/tools/eventmake", component: eventMaker },
1315
]
1416

1517
const router = createRouter({

0 commit comments

Comments
 (0)