Commit 12d3da3b authored by René Rösner's avatar René Rösner
Browse files

Merge branch 'main' into feature/354-design-richtlinien

parents 4aba305c bce54afc
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:vue/essential",
"standard"
],
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
"indent": [
"error",
4
],
"space-before-function-paren": [
"error",
{
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}
],
"eqeqeq": 0,
"array-callback-return": 0,
"id-length": [
"error",
{
"min": 4,
"exceptions": [
"alt",
"App",
"id",
"img",
"key",
"src",
"tag"
]
}
],
"comma-dangle": "off",
"@typescript-eslint/comma-dangle": [
"error",
{
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}
]
}
}
......@@ -4,9 +4,9 @@ type ChipOptions = {
}
export default ({ text, style }: ChipOptions) => {
return (
<div className={`m-px px-3 py-1 text-xs font-bold rounded-full text-white ${style} w-auto self-start shadow-sm`}>
{text}
</div>
);
};
return (
<div className={`m-px px-3 py-1 text-xs font-bold rounded-full text-white ${style} w-auto self-start shadow-sm`}>
{text}
</div>
)
}
import useBasePath from '../shared/use-base-path'
export default () => {
const basePath = useBasePath()
return (
<link rel="shortcut icon" href={`${basePath}/favicon-32x32.png`} />
)
}
import React, { Component, ReactElement } from 'react'
import React, { ReactElement } from 'react'
import { IconBooks } from '@tabler/icons'
type HeaderOptions = {
title: string
description: string
......@@ -13,43 +12,45 @@ type HeaderOptions = {
}
export default ({ title, description, img, children }: HeaderOptions) => {
return (
<section
className="bg-white mt-10 lg:mt-32 w-full mx-auto relative z-10 lg:pb-32"
aria-labelledby="heading"
>
<h2 className="sr-only" id="heading">
{title}
</h2>
<div className="flex flex-col bg-white rounded-b-lg shadow-xl">
<div className="flex-1 relative pt-24 px-6 pb-8 md:px-8">
<div className="h-32 absolute top-0 p-4 inline-block transform -translate-y-1/2">
<header className={'flex justify-between space-x-6'}>
{img && img.src ?(
<img
className={'w-24 h-24'}
src={img.src}
alt={img.alt}
/>
) : (
<IconBooks
className={'w-24 h-24'}
/>
)}
<h1 className="p-5 text-3xl lg:text-5xl tracking-tight text-gray-900 overflow-hidden">
return (
<section
className="bg-white mt-10 lg:mt-32 w-full mx-auto relative z-10 lg:pb-32"
aria-labelledby="heading"
>
<h2 className="sr-only" id="heading">
{title}
</h1>
</header>
</div>
<div
className="cms-blog-text text-xl text-gray-800 mt-14"
dangerouslySetInnerHTML={{ __html: description }}
/>
</div>
<div className="p-6 bg-gray-50 rounded-b-lg md:px-8 flex flex-row items-center gap-16">
{children}
</div>
</div>
</section>
)
</h2>
<div className="flex flex-col bg-white rounded-b-lg shadow-xl">
<div className="flex-1 relative pt-24 px-6 pb-8 md:px-8">
<div className="h-32 absolute top-0 p-4 inline-block transform -translate-y-1/2">
<header className={'flex justify-between space-x-6'}>
{img && img.src
? (
<img
className={'w-24 h-24'}
src={img.src}
alt={img.alt}
/>
)
: (
<IconBooks
className={'w-24 h-24'}
/>
)}
<h1 className="p-5 text-3xl lg:text-5xl tracking-tight text-gray-900 overflow-hidden">
{title}
</h1>
</header>
</div>
<div
className="cms-blog-text text-xl text-gray-800 mt-14"
dangerouslySetInnerHTML={{ __html: description }}
/>
</div>
<div className="p-6 bg-gray-50 rounded-b-lg md:px-8 flex flex-row items-center gap-16">
{children}
</div>
</div>
</section>
)
}
import Chip from "@/components/Chip";
import filterData from '@/lib/assets/data/currentFilter.json';
import Chip from '@/components/Chip'
import filterData from '@/lib/assets/data/currentFilter.json'
type ServiceTagOptions = {
text: string,
style: string
}
const filters = filterData.filter;
const filters = filterData.filter
const formatLabel = (text: string) => {
const label = 0;
const value = 1;
if (text.includes(':')){
const splittedLabel = text.split(':');
const label = 0
const value = 1
if (text.includes(':')) {
const splittedLabel = text.split(':')
return `${translateLabel(splittedLabel[label])}: ${translateValue(splittedLabel[label], splittedLabel[value])}`
}
return text;
};
return text
}
function translateLabel(label: string): string {
const filterCategoriesForTranslation = filters.filter(filterCategory => {
return filterCategory.id == label
});
return filterCategoriesForTranslation.length > 0 ? filterCategoriesForTranslation[0].label : '';
}
function translateLabel(label: string): string {
const filterCategoriesForTranslation = filters.filter(filterCategory => {
return filterCategory.id == label
})
return filterCategoriesForTranslation.length > 0 ? filterCategoriesForTranslation[0].label : ''
}
function translateValue(label: string, value: string): string {
function translateValue(label: string, value: string): string {
const filterCategoriesForTranslation = filters.filter(filterCategory => {
return filterCategory.id == label
});
return filterCategory.id == label
})
if (filterCategoriesForTranslation.length > 0) {
const filterCategory = filterCategoriesForTranslation[0];
const filterCategory = filterCategoriesForTranslation[0]
const filterValues = filterCategory.options.filter(option => {
return option.id == value
});
return filterValues.length > 0 ? filterValues[0].label : '';
})
return filterValues.length > 0 ? filterValues[0].label : ''
} else {
return '';
return ''
}
}
}
export default ({ text, style }: ServiceTagOptions) => {
return (
<Chip text={formatLabel(text)} style={`${style} capitalize ${text == 'label:external' ? 'hidden' : '' }`} />
);
};
return (
<Chip text={formatLabel(text)} style={`${style} capitalize ${text == 'label:external' ? 'hidden' : ''}`} />
)
}
import React, { useState, ReactElement } from "react";
import React, { useState, ReactElement } from 'react'
type TooltipOptions = {
children?: ReactElement[] | ReactElement
......@@ -9,34 +9,34 @@ type TooltipOptions = {
}
export default ({ delayIn, delayOut, direction, children, content }: TooltipOptions) => {
let timeout;
const [active, setActive] = useState(false);
let timeout
const [active, setActive] = useState(false)
const showTooltip = () => {
clearInterval(timeout);
timeout = setTimeout(() => {
setActive(true);
}, delayIn || 400);
};
const showTooltip = () => {
clearInterval(timeout)
timeout = setTimeout(() => {
setActive(true)
}, delayIn || 400)
}
const hideTooltip = () => {
clearInterval(timeout);
timeout = setTimeout(() => {
setActive(false);
}, delayOut || 400);
};
const hideTooltip = () => {
clearInterval(timeout)
timeout = setTimeout(() => {
setActive(false)
}, delayOut || 400)
}
return (
<div
className="tooltip-wrapper"
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
>
{children}
<div className={`tooltip-content ${direction || "top-left"} ${active ? 'active' : ''}`}>
<div className="tooltip-arrow"></div>
{content}
return (
<div
className="tooltip-wrapper"
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
>
{children}
<div className={`tooltip-content ${direction || 'top-left'} ${active ? 'active' : ''}`}>
<div className="tooltip-arrow"></div>
{content}
</div>
</div>
</div>
);
};
)
}
import Navbar from '@/views/layout/Navbar'
import { Footer, FooterColumn } from '@/views/layout/Footer'
import { useEffect } from 'react';
import { useEffect } from 'react'
export function Layout({ children }) {
useEffect(() => {
document.body.classList.add('absolute')
document.body.classList.add('lg:relative')
})
useEffect(() => {
document.body.classList.add("absolute");
document.body.classList.add("lg:relative");
});
return (
<>
{/* <Navbar
return (
<>
{/* <Navbar
logo={{
img: '/img/fitko-logo.svg',
alt: 'Föderale Entwicklungsportal',
}}
/> */}
<main className="lg:py-10">{children}</main>
<Footer logo={{
img: '/img/fitko-main-logo.svg',
alt: 'Föderale Entwicklungsportal',
}} copyright={'FITKO'}>
<FooterColumn title={'Rechtliches'} links={[
{label: 'Impressum', href: 'https://www.fitko.de/impressum' },
{label: 'Datenschutz', href: 'https://www.fitko.de/datenschutz' },
{label: 'Barrierefreiheit', href: 'https://www.fitko.de/barrierefreiheitserklaerung' },
]}/>
<FooterColumn title={''} links={[
{label: '', href: '/' },
]}/>
</Footer>
</>
)
<main className="lg:py-10">{children}</main>
<Footer logo={{
img: '/img/fitko-main-logo.svg',
alt: 'Föderale Entwicklungsportal',
}} copyright={'FITKO'}>
<FooterColumn title={'Rechtliches'} links={[
{ label: 'Impressum', href: 'https://www.fitko.de/impressum' },
{ label: 'Datenschutz', href: 'https://www.fitko.de/datenschutz' },
{ label: 'Barrierefreiheit', href: 'https://www.fitko.de/barrierefreiheitserklaerung' },
]} />
<FooterColumn title={''} links={[
{ label: '', href: '/' },
]} />
</Footer>
</>
)
}
......@@ -3,59 +3,69 @@
{
"label": "Art der Ressource",
"id": "type",
"options": [{
"label": "Plattformen",
"id": "platform",
"value": "platform"
},{
"label": "Basisdienste",
"id": "base",
"value": "base"
},{
"label": "Software",
"id": "software",
"value": "software"
},{
"label": "APIs",
"id": "api",
"value": "api"
},{
"label": "Information / Hilfestellung",
"id": "Information / Hilfestellung",
"value": "Information / Hilfestellung"
},{
"label": "Kollaboration",
"id": "Kollaboration",
"value": "Kollaboration"
},{
"label": "Vorgabe / Richtlinie",
"id": "Vorgabe / Richtlinie",
"value": "Vorgabe / Richtlinie"
}]
"options": [
{
"label": "Plattformen",
"id": "platform",
"value": "platform"
},
{
"label": "Basisdienste",
"id": "base",
"value": "base"
},
{
"label": "Software",
"id": "software",
"value": "software"
},
{
"label": "APIs",
"id": "api",
"value": "api"
},
{
"label": "Information / Hilfestellung",
"id": "Information / Hilfestellung",
"value": "Information / Hilfestellung"
},
{
"label": "Kollaboration",
"id": "Kollaboration",
"value": "Kollaboration"
},
{
"label": "Vorgabe / Richtlinie",
"id": "Vorgabe / Richtlinie",
"value": "Vorgabe / Richtlinie"
}
]
},
{
"label": "Status",
"id": "status",
"options": [{
"label": "Produktiv",
"id": "production",
"value": "production"
},
{
"label": "In Entwicklung",
"id": "development",
"value": "development"
},
{
"label": "Eingestellt",
"id": "discontinued",
"value": "discontinued"
},
{
"label": "Beta",
"id": "beta",
"value": "beta"
}]
"options": [
{
"label": "Produktiv",
"id": "production",
"value": "production"
},
{
"label": "In Entwicklung",
"id": "development",
"value": "development"
},
{
"label": "Eingestellt",
"id": "discontinued",
"value": "discontinued"
},
{
"label": "Beta",
"id": "beta",
"value": "beta"
}
]
}
]
}
\ No newline at end of file
import {
ContentfulClientApi,
createClient,
Entry,
EntryCollection,
ContentfulClientApi,
createClient,
Entry
} from 'contentful'
const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
const client: ContentfulClientApi = createClient({
space: space,
accessToken: accessToken,
space,
accessToken,
})
export type ServiceType = {
......@@ -41,20 +40,19 @@ export type Filter = {
}
export async function fetchServices(): Promise<Entry<any>[]> {
const services = await client.getEntries({
content_type: 'service',
})
if (services.items) return services.items
console.log(`Error getting Entries for services.`)
const services = await client.getEntries({
content_type: 'service',
})
if (services.items) return services.items
}
export async function fetchService(slug): Promise<Entry<any>> {
const services = await client.getEntries({
content_type: 'service',
})
return services.items.find(
(service: Entry<ServiceType>) => service.fields.slug === slug
)
const services = await client.getEntries({
content_type: 'service',
})
return services.items.find(
(service: Entry<ServiceType>) => service.fields.slug === slug
)
}
export default { fetchServices, fetchService }
import { MouseEvent } from 'react';
import { MouseEvent } from 'react'
export function removeFromObjRecursive(name: string, obj: any) {
export function removeFromObjRecursive(nodeName: string, nextJsDataObject: any) {
return JSON.parse(
JSON.stringify(obj, function (key, value) {
if (key !== name) return value;
JSON.stringify(nextJsDataObject, function (key, value) {
if (key !== nodeName) return value
})
);
)
}
export function replaceEmailsRecursive(name: string, obj: any) {
export function replaceEmailsRecursive(name: string, nextJsDataObject: any) {
return JSON.parse(
JSON.stringify(obj, function (key, value) {
if (key === name) return encodeEmail(value);
return value;
JSON.stringify(nextJsDataObject, function (key, value) {
if (key === name) return encodeEmail(value)
return value
})
);
)
}
export function encodeEmail(str: string) {
return btoa(str);
export function encodeEmail(emailAddress: string) {
return btoa(emailAddress)
}
export function decodeEmail(str: string) {
return atob(str);
export function decodeEmail(encodedEmailAddress: string) {
return atob(encodedEmailAddress)
}
export function handleMailtoEvent(e: MouseEvent<HTMLAnchorElement>) {
const el = e.currentTarget;
const base = el.dataset.base;