Compare commits

..

14 commits
v1.0.0 ... main

20 changed files with 5526 additions and 6211 deletions

View file

@ -8,7 +8,7 @@ Dieses Projekt, `ff-webpage-cms`, ist ein Content-Management-System (CMS) basier
Die Administrationsöberfläche ermöglicht die Verwaltung von Seiten und deren Inhalten wie Artikel, Termine, Einsätz oder Fahrzeuge. Seiten können auch über vordefinierte Schemata erstellt werden.
Eine Demo dieser Seite finden Sie unter [https://cms.ff-demo.jk-effects.cloud](https://cms.ff-demo.jk-effects.cloud).\
Eine Demo dieser Seite finden Sie unter [https://cms.webpage-demo.ff-admin.de](https://cms.webpage-demo.ff-admin.de).\
Die Zugangsdaten (Lesebeschränkt) sind: \
EMAIL: ff-demo@jk-effects.cloud\
PASSWORT: FFDemo1234\

6059
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "webpage-cms",
"version": "1.0.0",
"version": "1.1.0",
"private": true,
"description": "A Strapi application",
"scripts": {
@ -11,12 +11,12 @@
"strapi": "strapi"
},
"dependencies": {
"@offset-dev/strapi-calendar": "^1.0.0-beta.1",
"@strapi/plugin-color-picker": "^5.1.1",
"@strapi/plugin-documentation": "^5.1.1",
"@strapi/plugin-graphql": "^5.1.1",
"@strapi/plugin-users-permissions": "5.1.1",
"@strapi/strapi": "5.1.1",
"@offset-dev/strapi-calendar": "^1.0.0",
"@strapi/plugin-color-picker": "5.8.0",
"@strapi/plugin-documentation": "5.8.0",
"@strapi/plugin-graphql": "5.8.0",
"@strapi/plugin-users-permissions": "5.8.0",
"@strapi/strapi": "5.8.0",
"mysql2": "3.9.8",
"react": "^18.0.0",
"react-dom": "^18.0.0",

View file

@ -35,7 +35,7 @@
"image": {
"type": "media",
"multiple": false,
"required": true,
"required": false,
"allowedTypes": [
"images"
],

View file

@ -18,9 +18,9 @@
"unique": true
},
"collection": {
"type": "string",
"required": true,
"unique": true
"type": "enumeration",
"enum": ["events", "vehicles", "articles", "operations"],
"required": true
},
"image_item": {
"type": "boolean",

View file

@ -28,6 +28,28 @@
"targetField": "title",
"required": true
},
"content": {
"pluginOptions": {},
"type": "blocks"
},
"image": {
"type": "media",
"multiple": false,
"required": false,
"allowedTypes": [
"images"
],
"pluginOptions": {}
},
"attachment": {
"type": "media",
"multiple": true,
"required": false,
"allowedTypes": [
"images"
],
"pluginOptions": {}
},
"date": {
"pluginOptions": {},
"type": "datetime",

View file

@ -24,6 +24,11 @@
"repeatable": false,
"pluginOptions": {},
"component": "global.footer"
},
"SEO": {
"type": "component",
"repeatable": false,
"component": "shared.seo"
}
}
}

View file

@ -16,9 +16,12 @@
"type": "media",
"multiple": false,
"required": true,
"allowedTypes": [
"images"
]
"allowedTypes": ["images"]
},
"hide_backdrop": {
"type": "boolean",
"default": false,
"required": true
},
"content": {
"type": "dynamiczone",

View file

@ -28,6 +28,19 @@
"targetField": "title",
"required": true
},
"content": {
"pluginOptions": {},
"type": "blocks"
},
"image": {
"type": "media",
"multiple": false,
"required": false,
"allowedTypes": [
"images"
],
"pluginOptions": {}
},
"attachment": {
"type": "media",
"multiple": true,
@ -41,9 +54,6 @@
"pluginOptions": {},
"type": "datetime",
"required": true
},
"content": {
"type": "blocks"
}
}
}

View file

@ -41,7 +41,9 @@
"dynamic-zone.emphasise-article",
"dynamic-zone.dual-column-text",
"dynamic-zone.column-image-text",
"shared.list"
"shared.list",
"dynamic-zone.file-download",
"dynamic-zone.embedding"
]
}
}

View file

@ -4,7 +4,8 @@
"info": {
"singularName": "vehicle",
"pluralName": "vehicles",
"displayName": "Fahrzeuge"
"displayName": "Fahrzeuge",
"description": ""
},
"options": {
"draftAndPublish": true
@ -34,7 +35,7 @@
"image": {
"type": "media",
"multiple": false,
"required": true,
"required": false,
"allowedTypes": [
"images"
],
@ -48,6 +49,11 @@
"images"
],
"pluginOptions": {}
},
"date": {
"pluginOptions": {},
"type": "datetime",
"required": false
}
}
}

View file

@ -2,6 +2,27 @@
* vehicle controller
*/
import { factories } from '@strapi/strapi'
import { factories } from "@strapi/strapi";
export default factories.createCoreController('api::vehicle.vehicle');
export default factories.createCoreController("api::vehicle.vehicle", ({ strapi }) => ({
async distinctYears(ctx) {
try {
const years = await strapi.service("api::vehicle.vehicle").getDistinctYears();
ctx.body = years;
} catch (err) {
ctx.throw(500, err);
}
},
async findByYear(ctx) {
try {
const { year } = ctx.params;
const { page = "1", pageSize = "10" } = ctx.query as { page?: string; pageSize?: string };
const result = await strapi.service("api::vehicle.vehicle").findByYear(year, parseInt(page), parseInt(pageSize));
ctx.body = result;
} catch (err) {
ctx.throw(500, err);
}
},
}));

View file

@ -0,0 +1,14 @@
export default {
routes: [
{
method: "GET",
path: "/custom/vehicle/distinct-years",
handler: "api::vehicle.vehicle.distinctYears",
},
{
method: "GET",
path: "/custom/vehicle/year/:year",
handler: "api::vehicle.vehicle.findByYear",
},
],
};

View file

@ -2,6 +2,47 @@
* vehicle service
*/
import { factories } from '@strapi/strapi';
import { factories } from "@strapi/strapi";
import { parseISO, getYear } from "date-fns";
export default factories.createCoreService('api::vehicle.vehicle');
export default factories.createCoreService("api::vehicle.vehicle", ({ strapi }) => ({
async getDistinctYears() {
const articles = await strapi.query("api::vehicle.vehicle").findMany({
select: ["date"],
});
const years = articles
.map((article) => getYear(parseISO(article.date + "")))
.filter((year, index, self) => self.indexOf(year) === index)
.sort((a, b) => b - a);
return years;
},
async findByYear(year: string, page = 1, pageSize = 10) {
const startOfYear = new Date(`${year}-01-01T00:00:00.000Z`);
const endOfYear = new Date(`${year}-12-31T23:59:59.999Z`);
const articles = await strapi.query("api::vehicle.vehicle").findPage({
filters: {
date: {
$gte: startOfYear,
$lte: endOfYear,
},
publishedAt: {
$ne: null,
},
},
limit: pageSize,
page: page,
orderBy: { date: "desc" },
});
return {
data: articles.results,
meta: {
pagination: articles.pagination,
},
};
},
}));

View file

@ -0,0 +1,16 @@
{
"collectionName": "components_dynamic_zone_embedding",
"info": {
"displayName": "Einbettung"
},
"options": {},
"attributes": {
"title": {
"type": "string",
"required": true
},
"link": {
"type": "string"
}
}
}

View file

@ -0,0 +1,25 @@
{
"collectionName": "components_dynamic_zone_file_download",
"info": {
"displayName": "Datei-Download",
"description": ""
},
"options": {},
"attributes": {
"enable_download": {
"type": "boolean",
"default": true,
"required": true
},
"title": {
"type": "string",
"required": true
},
"file": {
"type": "media",
"multiple": false,
"required": true,
"allowedTypes": ["files", "images"]
}
}
}

View file

@ -0,0 +1,25 @@
{
"collectionName": "components_shared_seos",
"info": {
"displayName": "seo",
"icon": "search",
"description": ""
},
"options": {},
"attributes": {
"metaTitle": {
"required": true,
"type": "string",
"maxLength": 60
},
"metaDescription": {
"type": "string",
"required": true,
"minLength": 50
},
"keywords": {
"type": "text",
"regex": "[^,]+"
}
}
}

View file

@ -1,26 +1,24 @@
import type { Schema, Struct } from '@strapi/strapi';
import type { Schema, Struct } from "@strapi/strapi";
export interface DynamicZoneColumnImageText extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_column_image_texts';
collectionName: "components_dynamic_zone_column_image_texts";
info: {
description: '';
displayName: 'Text-Bild-Spalte';
icon: 'bulletList';
description: "";
displayName: "Text-Bild-Spalte";
icon: "bulletList";
};
attributes: {
image: Schema.Attribute.Media<'images'> & Schema.Attribute.Required;
image_left: Schema.Attribute.Boolean &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<true>;
image: Schema.Attribute.Media<"images"> & Schema.Attribute.Required;
image_left: Schema.Attribute.Boolean & Schema.Attribute.Required & Schema.Attribute.DefaultTo<true>;
text: Schema.Attribute.Blocks & Schema.Attribute.Required;
};
}
export interface DynamicZoneDualColumnText extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_dual_column_texts';
collectionName: "components_dynamic_zone_dual_column_texts";
info: {
displayName: 'Text-Text-Spalte';
icon: 'stack';
displayName: "Text-Text-Spalte";
icon: "stack";
};
attributes: {
left_side: Schema.Attribute.Blocks & Schema.Attribute.Required;
@ -28,41 +26,63 @@ export interface DynamicZoneDualColumnText extends Struct.ComponentSchema {
};
}
export interface DynamicZoneEmphasiseArticle extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_emphasise_articles';
export interface DynamicZoneEmbedding extends Struct.ComponentSchema {
collectionName: "components_dynamic_zone_embedding";
info: {
description: '';
displayName: 'Artikel hervorheben';
icon: 'dashboard';
displayName: "Einbettung";
};
attributes: {
articles: Schema.Attribute.Relation<'oneToMany', 'api::article.article'>;
base_url: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<'/artikel'>;
link: Schema.Attribute.String;
title: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface DynamicZoneEmphasiseArticle extends Struct.ComponentSchema {
collectionName: "components_dynamic_zone_emphasise_articles";
info: {
description: "";
displayName: "Artikel hervorheben";
icon: "dashboard";
};
attributes: {
articles: Schema.Attribute.Relation<"oneToMany", "api::article.article">;
base_url: Schema.Attribute.String & Schema.Attribute.Required & Schema.Attribute.DefaultTo<"/artikel">;
description: Schema.Attribute.Text;
titel: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface DynamicZoneFullImage extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_full_images';
export interface DynamicZoneFileDownload extends Struct.ComponentSchema {
collectionName: "components_dynamic_zone_file_download";
info: {
description: '';
displayName: 'Voll-Bild';
icon: 'dashboard';
description: "";
displayName: "Datei-Download";
};
attributes: {
image: Schema.Attribute.Media<'images'> & Schema.Attribute.Required;
enable_download: Schema.Attribute.Boolean & Schema.Attribute.Required & Schema.Attribute.DefaultTo<true>;
file: Schema.Attribute.Media<"files" | "images"> & Schema.Attribute.Required;
title: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface DynamicZoneFullImage extends Struct.ComponentSchema {
collectionName: "components_dynamic_zone_full_images";
info: {
description: "";
displayName: "Voll-Bild";
icon: "dashboard";
};
attributes: {
image: Schema.Attribute.Media<"images"> & Schema.Attribute.Required;
};
}
export interface DynamicZoneFullText extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_full_texts';
collectionName: "components_dynamic_zone_full_texts";
info: {
description: '';
displayName: 'Voll-Text';
icon: 'dashboard';
description: "";
displayName: "Voll-Text";
icon: "dashboard";
};
attributes: {
text: Schema.Attribute.Blocks & Schema.Attribute.Required;
@ -70,142 +90,157 @@ export interface DynamicZoneFullText extends Struct.ComponentSchema {
}
export interface DynamicZoneGallery extends Struct.ComponentSchema {
collectionName: 'components_dynamic_zone_galleries';
collectionName: "components_dynamic_zone_galleries";
info: {
description: '';
displayName: 'Galerie';
icon: 'apps';
description: "";
displayName: "Galerie";
icon: "apps";
};
attributes: {
images: Schema.Attribute.Media<'images', true> & Schema.Attribute.Required;
images: Schema.Attribute.Media<"images", true> & Schema.Attribute.Required;
};
}
export interface GlobalFooter extends Struct.ComponentSchema {
collectionName: 'components_global_footers';
collectionName: "components_global_footers";
info: {
description: '';
displayName: 'Fu\u00DFzeile';
icon: 'apps';
description: "";
displayName: "Fu\u00DFzeile";
icon: "apps";
};
attributes: {
copyright: Schema.Attribute.String;
designed_developed_by: Schema.Attribute.String;
links: Schema.Attribute.Component<'shared.link', true>;
links: Schema.Attribute.Component<"shared.link", true>;
};
}
export interface GlobalNavbar extends Struct.ComponentSchema {
collectionName: 'components_global_navbars';
collectionName: "components_global_navbars";
info: {
description: '';
displayName: 'Navigationsleiste';
icon: 'bold';
description: "";
displayName: "Navigationsleiste";
icon: "bold";
};
attributes: {
logo: Schema.Attribute.Media<'images'> & Schema.Attribute.Required;
navbar_items: Schema.Attribute.Component<'items.navbar-items', true>;
logo: Schema.Attribute.Media<"images"> & Schema.Attribute.Required;
navbar_items: Schema.Attribute.Component<"items.navbar-items", true>;
};
}
export interface ItemsNavbarItems extends Struct.ComponentSchema {
collectionName: 'components_items_left_navbar_items';
collectionName: "components_items_left_navbar_items";
info: {
description: '';
displayName: 'Navigations-\u00DCberpunkt';
icon: 'bulletList';
description: "";
displayName: "Navigations-\u00DCberpunkt";
icon: "bulletList";
};
attributes: {
default_active_child: Schema.Attribute.String;
name: Schema.Attribute.String;
navbar_sub_items: Schema.Attribute.Component<
'items.navbar-sub-items',
true
>;
page: Schema.Attribute.Relation<'oneToOne', 'api::page.page'>;
navbar_sub_items: Schema.Attribute.Component<"items.navbar-sub-items", true>;
page: Schema.Attribute.Relation<"oneToOne", "api::page.page">;
URL: Schema.Attribute.String;
};
}
export interface ItemsNavbarSubItems extends Struct.ComponentSchema {
collectionName: 'components_items_navbar_sub_items';
collectionName: "components_items_navbar_sub_items";
info: {
description: '';
displayName: 'Navigations-Unterpunkt';
icon: 'bulletList';
description: "";
displayName: "Navigations-Unterpunkt";
icon: "bulletList";
};
attributes: {
name: Schema.Attribute.String & Schema.Attribute.Required;
page: Schema.Attribute.Relation<'oneToOne', 'api::page.page'>;
page: Schema.Attribute.Relation<"oneToOne", "api::page.page">;
URL: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface SharedHero extends Struct.ComponentSchema {
collectionName: 'components_shared_heroes';
collectionName: "components_shared_heroes";
info: {
description: '';
displayName: 'hero';
icon: 'rocket';
description: "";
displayName: "hero";
icon: "rocket";
};
attributes: {
banner: Schema.Attribute.Media<'images'> & Schema.Attribute.Required;
banner: Schema.Attribute.Media<"images"> & Schema.Attribute.Required;
title: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface SharedLink extends Struct.ComponentSchema {
collectionName: 'components_shared_links';
collectionName: "components_shared_links";
info: {
description: '';
displayName: 'Link';
icon: 'link';
description: "";
displayName: "Link";
icon: "link";
};
attributes: {
target: Schema.Attribute.Enumeration<
['_blank', '_self', '_parent', '_top']
> &
target: Schema.Attribute.Enumeration<["_blank", "_self", "_parent", "_top"]> &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<'_self'>;
Schema.Attribute.DefaultTo<"_self">;
text: Schema.Attribute.String & Schema.Attribute.Required;
URL: Schema.Attribute.String & Schema.Attribute.Required;
};
}
export interface SharedList extends Struct.ComponentSchema {
collectionName: 'components_shared_lists';
collectionName: "components_shared_lists";
info: {
description: '';
displayName: 'Inhaltsauswahl';
icon: 'apps';
description: "";
displayName: "Inhaltsauswahl";
icon: "apps";
};
attributes: {
enable_detail: Schema.Attribute.Boolean &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<false>;
lookup: Schema.Attribute.Relation<
'oneToOne',
'api::collection-lookup.collection-lookup'
>;
enable_detail: Schema.Attribute.Boolean & Schema.Attribute.Required & Schema.Attribute.DefaultTo<false>;
lookup: Schema.Attribute.Relation<"oneToOne", "api::collection-lookup.collection-lookup">;
};
}
declare module '@strapi/strapi' {
export interface SharedSeo extends Struct.ComponentSchema {
collectionName: "components_shared_seos";
info: {
description: "";
displayName: "seo";
icon: "search";
};
attributes: {
keywords: Schema.Attribute.Text;
metaDescription: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 50;
}>;
metaTitle: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
maxLength: 60;
}>;
};
}
declare module "@strapi/strapi" {
export module Public {
export interface ComponentSchemas {
'dynamic-zone.column-image-text': DynamicZoneColumnImageText;
'dynamic-zone.dual-column-text': DynamicZoneDualColumnText;
'dynamic-zone.emphasise-article': DynamicZoneEmphasiseArticle;
'dynamic-zone.full-image': DynamicZoneFullImage;
'dynamic-zone.full-text': DynamicZoneFullText;
'dynamic-zone.gallery': DynamicZoneGallery;
'global.footer': GlobalFooter;
'global.navbar': GlobalNavbar;
'items.navbar-items': ItemsNavbarItems;
'items.navbar-sub-items': ItemsNavbarSubItems;
'shared.hero': SharedHero;
'shared.link': SharedLink;
'shared.list': SharedList;
"dynamic-zone.column-image-text": DynamicZoneColumnImageText;
"dynamic-zone.dual-column-text": DynamicZoneDualColumnText;
"dynamic-zone.embedding": DynamicZoneEmbedding;
"dynamic-zone.emphasise-article": DynamicZoneEmphasiseArticle;
"dynamic-zone.file-download": DynamicZoneFileDownload;
"dynamic-zone.full-image": DynamicZoneFullImage;
"dynamic-zone.full-text": DynamicZoneFullText;
"dynamic-zone.gallery": DynamicZoneGallery;
"global.footer": GlobalFooter;
"global.navbar": GlobalNavbar;
"items.navbar-items": ItemsNavbarItems;
"items.navbar-sub-items": ItemsNavbarSubItems;
"shared.hero": SharedHero;
"shared.link": SharedLink;
"shared.list": SharedList;
"shared.seo": SharedSeo;
}
}
}

File diff suppressed because it is too large Load diff