Add inline admin create forms to home page components
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 28s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 28s
Lazy-load create forms (Post, Activity, Favorite, Rowing) directly into their corresponding home components with an admin-only toggle button, replacing the need to navigate to the admin page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ import Button from "@/components/input/Button.vue";
|
||||
import { ref } from "vue";
|
||||
import { gql } from "@/graphql";
|
||||
|
||||
const emit = defineEmits(["done", "cancel"]);
|
||||
|
||||
const type = ref("");
|
||||
const name = ref("");
|
||||
const link = ref("");
|
||||
@@ -18,6 +20,7 @@ async function post() {
|
||||
name.value = "";
|
||||
link.value = "";
|
||||
console.log(data.createActivity);
|
||||
emit("done");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@@ -31,5 +34,6 @@ async function post() {
|
||||
<input type="text" v-model="name" placeholder="Name" @keyup.enter="post" />
|
||||
<input type="text" v-model="link" placeholder="Link" @keyup.enter="post" />
|
||||
<Button @click="post">Upload</Button>
|
||||
<Button @click="emit('cancel')">Cancel</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,6 +4,8 @@ import Button from "@/components/input/Button.vue";
|
||||
import { ref } from "vue";
|
||||
import { gql } from "@/graphql";
|
||||
|
||||
const emit = defineEmits(["done", "cancel"]);
|
||||
|
||||
const type = ref("");
|
||||
const name = ref("");
|
||||
const link = ref("");
|
||||
@@ -18,6 +20,7 @@ async function post() {
|
||||
name.value = "";
|
||||
link.value = "";
|
||||
console.log(data.createFavorite);
|
||||
emit("done");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@@ -31,5 +34,6 @@ async function post() {
|
||||
<input type="text" v-model="name" placeholder="Name" @keyup.enter="post" />
|
||||
<input type="text" v-model="link" placeholder="Link" @keyup.enter="post" />
|
||||
<Button @click="post">Upload</Button>
|
||||
<Button @click="emit('cancel')">Cancel</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,6 +3,8 @@ import Button from "@/components/input/Button.vue";
|
||||
import { ref } from "vue";
|
||||
import { gql } from "@/graphql";
|
||||
|
||||
const emit = defineEmits(["done", "cancel"]);
|
||||
|
||||
const title = ref("");
|
||||
const content = ref("");
|
||||
|
||||
@@ -15,6 +17,7 @@ async function post() {
|
||||
title.value = "";
|
||||
content.value = "";
|
||||
console.log(data.createPost);
|
||||
emit("done");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@@ -31,6 +34,6 @@ async function post() {
|
||||
placeholder="Content"
|
||||
></textarea>
|
||||
<Button @click="post">Upload</Button>
|
||||
<!-- make textarea take up most the space -->
|
||||
<Button @click="emit('cancel')">Cancel</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,6 +3,8 @@ import Button from "@/components/input/Button.vue";
|
||||
import { ref } from "vue";
|
||||
import axios from "axios";
|
||||
|
||||
const emit = defineEmits(["done", "cancel"]);
|
||||
|
||||
const images = ref([]);
|
||||
const results = ref([]);
|
||||
|
||||
@@ -35,6 +37,7 @@ async function submit() {
|
||||
);
|
||||
|
||||
images.value = [];
|
||||
emit("done");
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -43,6 +46,7 @@ async function submit() {
|
||||
<h1>Create Rowing</h1>
|
||||
<input type="file" accept="image/jpeg,image/png,image/gif,image/webp" multiple @change="onFileChange" />
|
||||
<Button @click="submit">Upload</Button>
|
||||
<Button @click="emit('cancel')">Cancel</Button>
|
||||
<div v-for="r in results" :key="r.name">
|
||||
<span class="text-primary">{{ r.name }}: </span>
|
||||
<span :class="r.ok ? 'text-secondary' : 'text-red-500'">{{ r.status }}</span>
|
||||
|
||||
@@ -3,15 +3,29 @@ import AutoScroll from "@/components/util/AutoScroll.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
|
||||
import { ref, defineAsyncComponent } from "vue";
|
||||
import { useActivityStore } from "@/stores/activity";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
const CreateActivity = defineAsyncComponent(() => import("@/views/admin/CreateActivity.vue"));
|
||||
|
||||
const activityStore = useActivityStore();
|
||||
const authStore = useAuthStore();
|
||||
const showCreate = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-center">
|
||||
<Header>Consumption</Header>
|
||||
<AutoScroll class="flex-1 w-full">
|
||||
<Header>
|
||||
<span class="flex items-center justify-between w-full">
|
||||
{{ showCreate ? "Create Activity" : "Consumption" }}
|
||||
<button v-if="authStore.user.admin" class="text-sm px-1" @click="showCreate = !showCreate">
|
||||
{{ showCreate ? "x" : "+" }}
|
||||
</button>
|
||||
</span>
|
||||
</Header>
|
||||
<CreateActivity v-if="showCreate" class="flex-1 w-full p-1" @done="showCreate = false" @cancel="showCreate = false" />
|
||||
<AutoScroll v-if="!showCreate" class="flex-1 w-full">
|
||||
<LinkTable variant="table" class="w-full" :items="activityStore.activity" />
|
||||
</AutoScroll>
|
||||
</div>
|
||||
|
||||
@@ -3,15 +3,29 @@ import Header from "@/components/text/Header.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import AutoScroll from "@/components/util/AutoScroll.vue";
|
||||
|
||||
import { ref, defineAsyncComponent } from "vue";
|
||||
import { useFavoritesStore } from "@/stores/favorites";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
const CreateFavorite = defineAsyncComponent(() => import("@/views/admin/CreateFavorite.vue"));
|
||||
|
||||
const favoritesStore = useFavoritesStore();
|
||||
const authStore = useAuthStore();
|
||||
const showCreate = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-center">
|
||||
<Header>favs</Header>
|
||||
<AutoScroll class="w-full flex-1">
|
||||
<Header>
|
||||
<span class="flex items-center justify-between w-full">
|
||||
{{ showCreate ? "Create Favorite" : "favs" }}
|
||||
<button v-if="authStore.user.admin" class="text-sm px-1" @click="showCreate = !showCreate">
|
||||
{{ showCreate ? "x" : "+" }}
|
||||
</button>
|
||||
</span>
|
||||
</Header>
|
||||
<CreateFavorite v-if="showCreate" class="w-full flex-1 p-1" @done="showCreate = false" @cancel="showCreate = false" />
|
||||
<AutoScroll v-if="!showCreate" class="w-full flex-1">
|
||||
<LinkTable
|
||||
variant="table"
|
||||
class="w-full"
|
||||
|
||||
@@ -3,14 +3,17 @@ import Button from "@/components/input/Button.vue";
|
||||
import Markdown from "@/components/util/Markdown.vue";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import { ref, computed, defineAsyncComponent } from "vue";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { usePostsStore } from "@/stores/posts";
|
||||
|
||||
const CreatePost = defineAsyncComponent(() => import("@/views/admin/CreatePost.vue"));
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const postsStore = usePostsStore();
|
||||
|
||||
const idx = ref(0);
|
||||
const showCreate = ref(false);
|
||||
|
||||
const leftCap = computed(() => idx.value === 0);
|
||||
const rightCap = computed(() => idx.value === postsStore.postsCount - 1);
|
||||
@@ -39,8 +42,17 @@ function deletePost() {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col flex-1 min-h-0">
|
||||
<Header>{{ post.title }}</Header>
|
||||
<Header>
|
||||
<span class="flex items-center justify-between w-full">
|
||||
{{ showCreate ? "Create Post" : post.title }}
|
||||
<button v-if="authStore.user.admin" class="text-sm px-1" @click="showCreate = !showCreate">
|
||||
{{ showCreate ? "x" : "+" }}
|
||||
</button>
|
||||
</span>
|
||||
</Header>
|
||||
<CreatePost v-if="showCreate" class="flex-1 min-h-0 p-1" @done="showCreate = false" @cancel="showCreate = false" />
|
||||
<div
|
||||
v-if="!showCreate"
|
||||
class="flex flex-col flex-1 min-h-0 p-1 overflow-auto text-left items-start justify-start"
|
||||
>
|
||||
<small
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { ref, computed, defineAsyncComponent } from "vue";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import { useHomeDataStore } from "@/stores/homeData";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const CreateRowing = defineAsyncComponent(() => import("@/views/admin/CreateRowing.vue"));
|
||||
|
||||
const store = useHomeDataStore();
|
||||
const authStore = useAuthStore();
|
||||
const { loaded, error, rowingSessions } = storeToRefs(store);
|
||||
const showCreate = ref(false);
|
||||
|
||||
const rows = computed(() => rowingSessions.value.slice().reverse());
|
||||
const loading = computed(() => !loaded.value);
|
||||
@@ -109,9 +114,17 @@ function formatValue(key, val) {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col h-full overflow-hidden">
|
||||
<Header>Rowing</Header>
|
||||
<Header>
|
||||
<span class="flex items-center justify-between w-full">
|
||||
{{ showCreate ? "Upload Rowing" : "Rowing" }}
|
||||
<button v-if="authStore.user.admin" class="text-sm px-1" @click="showCreate = !showCreate">
|
||||
{{ showCreate ? "x" : "+" }}
|
||||
</button>
|
||||
</span>
|
||||
</Header>
|
||||
|
||||
<div v-if="loading" class="flex-1 flex items-center justify-center">
|
||||
<CreateRowing v-if="showCreate" class="flex-1 p-1" @done="showCreate = false" @cancel="showCreate = false" />
|
||||
<div v-else-if="loading" class="flex-1 flex items-center justify-center">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div v-else-if="error" class="flex-1 flex items-center justify-center">
|
||||
|
||||
Reference in New Issue
Block a user