feat(footer): create footer with backend-provided metadata
This commit is contained in:
@@ -2,9 +2,11 @@
|
|||||||
<div class="min-h-screen flex flex-col">
|
<div class="min-h-screen flex flex-col">
|
||||||
<StaHeader />
|
<StaHeader />
|
||||||
<main class="grow px-6 py-10 max-w-4xl mx-auto w-full"></main>
|
<main class="grow px-6 py-10 max-w-4xl mx-auto w-full"></main>
|
||||||
|
<StaFooter />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import StaHeader from './components/StaHeader.vue';
|
import StaHeader from './components/StaHeader.vue';
|
||||||
|
import StaFooter from './components/StaFooter.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
36
src/components/StaFooter.vue
Normal file
36
src/components/StaFooter.vue
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<footer
|
||||||
|
class="bg-background-900 border-t border-background-900 px-6 py-4 text-sm text-text"
|
||||||
|
>
|
||||||
|
<div class="max-w-4xl mx-auto text-center">
|
||||||
|
© {{ currentYear }} {{ appName }} ‐ Lucien Cartier-Tilet.
|
||||||
|
<a href="https://labs.phundrak.com/phundrak/sta" class="text-accent">
|
||||||
|
Source code
|
||||||
|
</a>
|
||||||
|
under the
|
||||||
|
<a
|
||||||
|
href="https://labs.phundrak.com/phundrak/sta/src/branch/develop/LICENSE.md"
|
||||||
|
class="text-accent"
|
||||||
|
>
|
||||||
|
AGPL 3.0 license </a
|
||||||
|
>.
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useMeta } from '../composables/useMeta';
|
||||||
|
import { isNil } from '../utils/isNil';
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
|
const { metadata } = useMeta();
|
||||||
|
const appName = computed(() =>
|
||||||
|
isNil(metadata.value)
|
||||||
|
? 'STA'
|
||||||
|
: `${metadata.value.name} v${metadata.value.version}`,
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less"></style>
|
||||||
29
src/composables/useMeta.ts
Normal file
29
src/composables/useMeta.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import type { components } from '../api/schema';
|
||||||
|
import { apiClient } from '../api/client';
|
||||||
|
|
||||||
|
type Meta = components['schemas']['Meta'];
|
||||||
|
|
||||||
|
export function useMeta() {
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const metadata = ref<Meta | null>(null);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
const getMetadata = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
const { data } = await apiClient.GET('/api/meta');
|
||||||
|
error.value = null;
|
||||||
|
metadata.value = data as Meta;
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('Failed to fetch metadata:', err);
|
||||||
|
error.value = err.message || 'Failed to fetch metadata';
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(getMetadata);
|
||||||
|
|
||||||
|
return { isLoading, metadata, error };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user