Compare commits

...

5 commits
v1.0.3 ... main

Author SHA1 Message Date
679623f4dd weburl change 2025-01-18 14:58:55 +01:00
13b7ab4805 1.1.0 2025-01-18 11:48:54 +01:00
69fd756a5a embedding 2025-01-18 11:39:03 +01:00
9d81666a3c file download component 2025-01-18 11:30:46 +01:00
2189a3d33b hide backdrop option and smooth scroll down 2025-01-17 11:34:36 +01:00
21 changed files with 119 additions and 27 deletions

View file

@ -1,12 +1,12 @@
# ff-webpage
Feuerwehr Webseite zu Strapi Contnet Management
Feuerwehr Webseite zu Strapi Content Management
## Einleitung
Dieses Repository dient zur dynamischen Erstellung von Webseiten. Es ist ein Frontend-Client, der auf die Daten des [Strapi Content Management Systems (CMS)](https://forgejo.jk-effects.cloud/Ehrenamt/ff-webpage-cms) zugreift. Die Webseite wird mit Nuxt.js erstellt und bietet eine benutzerfreundliche Oberfläche für die Anzeige von Inhalten. Die Webseite ist für Feuerwehren konzipiert und bietet eine einfache Möglichkeit, Informationen zu veröffentlichen und zu verwalten.
Eine Demo dieser Seite finden Sie unter [https://ff-demo.jk-effects.cloud](https://ff-demo.jk-effects.cloud).
Eine Demo dieser Seite finden Sie unter [https://webpage-demo.ff-admin.de](https://webpage-demo.ff-admin.de).
## Installation

View file

@ -9,6 +9,8 @@
<DynamicZoneFullImage v-else-if="item.__component == 'dynamic-zone.full-image'" :data="item" />
<DynamicZoneFullText v-else-if="item.__component == 'dynamic-zone.full-text'" :data="item" />
<DynamicZoneGallery v-else-if="item.__component == 'dynamic-zone.gallery'" :data="item" />
<DynamicZoneFileDownload v-else-if="item.__component == 'dynamic-zone.file-download'" :data="item" />
<DynamicZoneEmbedding v-else-if="item.__component == 'dynamic-zone.embedding'" :data="item" />
<SharedList v-else-if="item.__component == 'shared.list'" :data="item" />
<br />
</div>

View file

@ -0,0 +1,15 @@
<template>
<div class="flex flex-col gap-2 w-full min-h-fit max-w-4xl mx-auto">
<h1 class="text-center">{{ data.title }}</h1>
<iframe :src="data.link" class="w-full h-[90vh]"></iframe>
</div>
</template>
<script setup lang="ts">
import type { PropType } from "vue";
import type DynamicZoneEmbedding from "../../types/component/dynamicZoneEmbedding";
const props = defineProps({
data: Object as PropType<DynamicZoneEmbedding>,
});
</script>

View file

@ -0,0 +1,42 @@
<template>
<div v-if="showComponent" class="flex flex-col gap-2 w-full min-h-fit max-w-4xl mx-auto">
<h1 class="text-center">{{ data.title }}</h1>
<iframe v-if="data.file.mime == 'application/pdf'" :src="baseUrl + data.file.url" class="w-full h-[90vh]"></iframe>
<NuxtPicture
v-if="data.file.mime.includes('image')"
loading="lazy"
class="w-full object-cover object-center mx-auto"
:src="baseUrl + data?.file.url"
:imgAttrs="{ class: 'w-full h-full object-cover object-center' }"
/>
<a
v-if="data.enable_download"
:href="baseUrl + data.file.url"
:download="data.file.name"
target="_blank"
class="w-fit text-primary underline"
>
Datei herunterladen
</a>
</div>
</template>
<script setup lang="ts">
import type { PropType } from "vue";
import type DynamicZoneFileDownload from "../../types/component/dynamicZoneFileDownload";
const runtimeConfig = useRuntimeConfig();
const baseUrl = runtimeConfig.public.strapi.url;
const props = defineProps({
data: Object as PropType<DynamicZoneFileDownload>,
});
const showComponent = computed(() => {
if (props.data.file.mime == "application/pdf" || props.data.file.mime.includes("image")) {
return true;
} else {
return props.data.enable_download;
}
});
</script>

View file

@ -1,5 +1,5 @@
<template>
<div class="relative h-[calc(100svh-6rem)] max-h-[calc(100svh-6rem)] w-full overflow-hidden">
<div v-if="!hide_backdrop" class="relative h-[calc(100svh-6rem)] max-h-[calc(100svh-6rem)] w-full overflow-hidden">
<NuxtPicture
loading="lazy"
class="w-full h-full object-cover object-center"
@ -7,6 +7,11 @@
:imgAttrs="{ class: 'w-full h-full object-cover object-center' }"
/>
<img class="absolute p-4 max-sm:w-full sm:h-40 bottom-5" :src="baseUrl + navbar.logo.url" />
<img
class="absolute h-5 w-5 left-1/2 -translate-y-1/2 bottom-5 text-gray-400 cursor-pointer"
src="/chevrons-down.svg"
@click="scroll()"
/>
</div>
<Header />
<slot />
@ -28,5 +33,9 @@ const { data: global } = await useAsyncData("global", () => findOne<Global>("glo
const { navbar } = global.value?.data as unknown as Global;
const { data: homepage } = await useAsyncData("homepage", () => findOne<Homepage>("homepage"));
const { backdrop } = homepage.value?.data as unknown as Homepage;
const { backdrop, hide_backdrop } = homepage.value?.data as unknown as Homepage;
function scroll() {
window.scrollTo({ top: window.innerHeight - 96, behavior: "smooth" });
}
</script>

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "nuxt-app",
"version": "1.0.3",
"version": "1.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nuxt-app",
"version": "1.0.3",
"version": "1.1.0",
"hasInstallScript": true,
"dependencies": {
"@nuxt/image": "^1.8.1",

View file

@ -21,5 +21,5 @@
"postcss": "^8.4.47",
"tailwindcss": "^3.4.14"
},
"version": "1.0.3"
"version": "1.1.0"
}

1
public/chevrons-down.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-down"><polyline points="7 13 12 18 17 13"></polyline><polyline points="7 6 12 11 17 6"></polyline></svg>

After

Width:  |  Height:  |  Size: 317 B

View file

@ -1,4 +1,4 @@
import type BaseImage from "../component/baseImage";
import type BaseFile from "../component/baseFile";
import type BaseCollection from "./baseCollection";
export default interface Article extends BaseCollection {}

View file

@ -1,4 +1,4 @@
import type BaseImage from "../component/baseImage";
import type BaseFile from "../component/baseFile";
import type ContentField from "../field/content";
export default interface BaseCollection {
@ -14,6 +14,6 @@ export default interface BaseCollection {
description: string;
date: string | undefined;
content: ContentField | undefined;
image: BaseImage | undefined;
attachment: Array<BaseImage>;
image: BaseFile | undefined;
attachment: Array<BaseFile>;
}

View file

@ -1,4 +1,4 @@
import type BaseImage from "../component/baseImage";
import type BaseFile from "../component/baseFile";
import type BaseCollection from "./baseCollection";
export default interface Vehicle extends BaseCollection {

View file

@ -4,7 +4,9 @@ import type DynamicZoneEmphasiseArticle from "./dynamicZoneEmphasiseArticle";
import type DynamicZoneFullImage from "./dynamicZoneFullImage";
import type DynamicZoneFullText from "./dynamicZoneFullText";
import type DynamicZoneGallery from "./dynamicZoneGallery";
import type DynamicZoneFileDownload from "./dynamicZoneFileDownload";
import type SharedList from "./sharedList";
import type DynamicZoneEmbedding from "./dynamicZoneEmbedding";
export default interface BaseComponent {
__component: ComponentNames;
@ -18,7 +20,9 @@ export type ComponentNames =
| "dynamic-zone.full-image"
| "dynamic-zone.emphasise-article"
| "dynamic-zone.dual-column-text"
| "dynamic-zone.column-image-text";
| "dynamic-zone.column-image-text"
| "dynamic-zone.file-download"
| "dynamic-zone.embedding";
export type ComponentTypes =
| SharedList
@ -27,4 +31,6 @@ export type ComponentTypes =
| DynamicZoneFullImage
| DynamicZoneEmphasiseArticle
| DynamicZoneDualColumnText
| DynamicZoneColumnImageText;
| DynamicZoneColumnImageText
| DynamicZoneFileDownload
| DynamicZoneEmbedding;

View file

@ -1,4 +1,4 @@
export default interface BaseImage {
export default interface BaseFile {
id: number;
documentId: string;
name: string;

View file

@ -1,10 +1,10 @@
import type ContentField from "../field/content";
import type BaseComponent from "./baseComponent";
import type BaseImage from "./baseImage";
import type BaseFile from "./baseFile";
export default interface DynamicZoneColumnImageText extends BaseComponent {
__component: "dynamic-zone.column-image-text";
text: ContentField;
image_left: boolean;
image: BaseImage;
image: BaseFile;
}

View file

@ -0,0 +1,7 @@
import type BaseComponent from "./baseComponent";
export default interface DynamicZoneEmbedding extends BaseComponent {
__component: "dynamic-zone.embedding";
title: string;
link: string;
}

View file

@ -0,0 +1,9 @@
import type BaseComponent from "./baseComponent";
import type BaseFile from "./baseFile";
export default interface DynamicZoneFileDownload extends BaseComponent {
__component: "dynamic-zone.file-download";
enable_download: boolean;
title: string;
file: BaseFile;
}

View file

@ -1,7 +1,7 @@
import type BaseComponent from "./baseComponent";
import type BaseImage from "./baseImage";
import type BaseFile from "./baseFile";
export default interface DynamicZoneFullImage extends BaseComponent {
__component: "dynamic-zone.full-image";
image: BaseImage;
image: BaseFile;
}

View file

@ -1,7 +1,7 @@
import type BaseComponent from "./baseComponent";
import type BaseImage from "./baseImage";
import type BaseFile from "./baseFile";
export default interface DynamicZoneGallery extends BaseComponent {
__component: "dynamic-zone.gallery";
images: Array<BaseImage>;
images: Array<BaseFile>;
}

View file

@ -1,8 +1,8 @@
import type BaseImage from "./baseImage";
import type BaseFile from "./baseFile";
import type NavbarItem from "./itemsNavbarItem";
export default interface Navbar {
id: number;
logo: BaseImage;
logo: BaseFile;
navbar_items: NavbarItem[];
}

View file

@ -1,7 +1,7 @@
import type BaseImage from "./baseImage";
import type BaseFile from "./baseFile";
export default interface SharedHero {
id: number;
title: string;
banner: BaseImage;
banner: BaseFile;
}

View file

@ -1,4 +1,4 @@
import type BaseImage from "../component/baseImage";
import type BaseFile from "../component/baseFile";
import type { ComponentTypes } from "../component/baseComponent";
export default interface Homepage {
@ -8,6 +8,7 @@ export default interface Homepage {
updatedAt: string;
publishedAt: string;
locale: string;
backdrop: BaseImage;
backdrop: BaseFile;
hide_backdrop: boolean;
content: Array<ComponentTypes>;
}