Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (7)
Showing
with 241 additions and 185 deletions
...@@ -117,4 +117,4 @@ yarn-audit: ...@@ -117,4 +117,4 @@ yarn-audit:
stage: cve-scan stage: cve-scan
image: node:lts-alpine image: node:lts-alpine
script: script:
- yarn audit --level high || (test $? -eq 4 && echo "Moderate vulnerabilities found, proceeding anyway.") - yarn audit --level high || (test $? -lt 8 && echo "Moderate vulnerabilities found, proceeding anyway.")
...@@ -8,7 +8,7 @@ type ServiceTagOptions = { ...@@ -8,7 +8,7 @@ type ServiceTagOptions = {
} }
const formatLabel = (tag: Tag) => { const formatLabel = (tag: Tag) => {
return `${translateLabel(tag.name)}: ${translateTag(tag)}` return `${translateLabel(tag?.name)}: ${translateTag(tag)}`
} }
export default ({ tag, style }: ServiceTagOptions) => { export default ({ tag, style }: ServiceTagOptions) => {
......
---
name: Routing-API
link: https://docs.fitko.de/fit-connect/docs/apis/routing-api
icon: IconRoute
order: 0
---
Um einen Antrag maschinenlesbar an die fachlich zuständige Stelle zu übermitteln, können Informationen über Zuständigkeiten und technische Parameter über die Routing API ermittelt werden. Der Abruf dieser Parameter erfolgt über eine Anfrage an den FIT-Connect Routingdienst.
\ No newline at end of file
---
name: Routing-API
link: https://docs.fitko.de/fit-connect/docs/apis/routing-api
icon: IconRoute
---
Um einen Antrag maschinenlesbar an die fachlich zuständige Stelle zu übermitteln, können Informationen über Zuständigkeiten und technische Parameter über die Routing API ermittelt werden. Der Abruf dieser Parameter erfolgt über eine Anfrage an den FIT-Connect Routingdienst.
\ No newline at end of file
---
name: Standards und Schnittstellen
link: https://docs.fitko.de/standards-und-schnittstellen/
icon: IconSteeringWheel
---
Im Rahmen der Umsetzung des Portalverbunds wurden die Kommunikationsbeziehungen zwischen den verschiedenen Basisdiensten wie Servicekonten, Postfächern und ePayment-Lösungen analysiert und in einer Übersicht der eingesetzten Standards und Schnittstellen dokumentiert.
\ No newline at end of file
---
name: Submission-API
link: https://docs.fitko.de/fit-connect/docs/apis/submission-api
icon: IconSend
---
Um einen Antrag maschinenlesbar an die fachlich zuständige Stelle zu übermitteln, können Informationen über Zuständigkeiten und technische Parameter über die Routing API ermittelt werden. Der Abruf dieser Parameter erfolgt über eine Anfrage an den FIT-Connect Routingdienst.
\ No newline at end of file
---
name: Routing-API
link: https://docs.fitko.de/fit-connect/docs/apis/routing-api
icon: IconRoute
---
Um einen Antrag maschinenlesbar an die fachlich zuständige Stelle zu übermitteln, können Informationen über Zuständigkeiten und technische Parameter über die Routing API ermittelt werden. Der Abruf dieser Parameter erfolgt über eine Anfrage an den FIT-Connect Routingdienst.
\ No newline at end of file
---
name: Standards und Schnittstellen
link: https://docs.fitko.de/standards-und-schnittstellen/
icon: IconSteeringWheel
---
Im Rahmen der Umsetzung des Portalverbunds wurden die Kommunikationsbeziehungen zwischen den verschiedenen Basisdiensten wie Servicekonten, Postfächern und ePayment-Lösungen analysiert und in einer Übersicht der eingesetzten Standards und Schnittstellen dokumentiert.
\ No newline at end of file
---
name: Submission-API
link: https://docs.fitko.de/fit-connect/docs/apis/submission-api
icon: IconSend
---
Um einen Antrag maschinenlesbar an die fachlich zuständige Stelle zu übermitteln, können Informationen über Zuständigkeiten und technische Parameter über die Routing API ermittelt werden. Der Abruf dieser Parameter erfolgt über eine Anfrage an den FIT-Connect Routingdienst.
\ No newline at end of file
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
"remark-html": "^15.0.2", "remark-html": "^15.0.2",
"sass": "^1.58.3", "sass": "^1.58.3",
"semver": "^7.5.2", "semver": "^7.5.2",
"unified": "^11.0.0" "unified": "^11.0.0",
"yaml": "^2.3.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.22.5", "@babel/core": "^7.22.5",
......
...@@ -16,12 +16,14 @@ import { ServiceContent } from 'types/ServiceContent' ...@@ -16,12 +16,14 @@ import { ServiceContent } from 'types/ServiceContent'
import { Tag } from 'types/content/' import { Tag } from 'types/content/'
import useContent from 'shared/use-content' import useContent from 'shared/use-content'
import useImgPath from 'shared/use-img-path' import useImgPath from 'shared/use-img-path'
import useTranslation from '../../shared/use-translation'
export default function ({ contentsString }) { export default function ({ contentsString }) {
const contents: ServiceContent[] = JSON.parse(contentsString) const contents: ServiceContent[] = JSON.parse(contentsString)
const router = useRouter() const router = useRouter()
const filters = filterData.filter const filters = filterData.filter
const { filteredServices, activeTagFilters, filterToParams } = useServiceFilter(contents, router.query.filter) const { filteredServices, activeTagFilters, filterToParams } = useServiceFilter(contents, router.query.filter)
const { getImgPath } = useImgPath() const { getImgPath } = useImgPath()
const { translate } = useTranslation()
function handleFilters(event) { function handleFilters(event) {
const filter = event.target.id.split('-')[0] const filter = event.target.id.split('-')[0]
...@@ -35,7 +37,7 @@ export default function ({ contentsString }) { ...@@ -35,7 +37,7 @@ export default function ({ contentsString }) {
} }
const hasContentTag = (content: ServiceContent, tagName: string) => { const hasContentTag = (content: ServiceContent, tagName: string) => {
const tags: Tag[] = content.tags.filter(tag => tag.name + ':' + tag.value === tagName) const tags: Tag[] = content.tags.filter(tag => tag?.name + ':' + tag?.value === tagName)
return tags.length > 0 return tags.length > 0
} }
...@@ -49,7 +51,7 @@ export default function ({ contentsString }) { ...@@ -49,7 +51,7 @@ export default function ({ contentsString }) {
<div className="lg:block md:space-x-10 hidden"> <div className="lg:block md:space-x-10 hidden">
<Link href="/" passHref legacyBehavior> <Link href="/" passHref legacyBehavior>
<a className={'text-lg font-bold text-yellow-400 hover:text-gray-900'}> <a className={'text-lg font-bold text-yellow-400 hover:text-gray-900'}>
Föderales Entwicklungsportal { translate('resources.buttons.backhome')}
</a> </a>
</Link> </Link>
</div> </div>
...@@ -72,7 +74,7 @@ export default function ({ contentsString }) { ...@@ -72,7 +74,7 @@ export default function ({ contentsString }) {
</div> </div>
<h1> <h1>
<span className="overflow-hiddenmt-1 block text-4xl tracking-tight sm:text-5xl xl:text-7xl"> <span className="overflow-hiddenmt-1 block text-4xl tracking-tight sm:text-5xl xl:text-7xl">
<span className="block text-gray-900">Verfügbare Plattformen &amp; Basisdienste</span> <span className="block text-gray-900">{translate('resources.headlines.title')}</span>
</span> </span>
</h1> </h1>
</header> </header>
...@@ -181,7 +183,7 @@ export default function ({ contentsString }) { ...@@ -181,7 +183,7 @@ export default function ({ contentsString }) {
<span className="inline-flex items-center text-sm mx-5 xl:mx-12"> <span className="inline-flex items-center text-sm mx-5 xl:mx-12">
<Link href={`${service.docsUrl}`} passHref legacyBehavior> <Link href={`${service.docsUrl}`} passHref legacyBehavior>
<a className="inline-flex space-x-2 text-gray-400 hover:text-gray-800"> <a className="inline-flex space-x-2 text-gray-400 hover:text-gray-800">
<span className="font-medium">Direkt zur Ressource</span> <span className="font-medium">{translate('resources.buttons.toresource')}</span>
<IconBook2 <IconBook2
className="h-5 w-5" className="h-5 w-5"
aria-hidden="true" aria-hidden="true"
...@@ -192,7 +194,7 @@ export default function ({ contentsString }) { ...@@ -192,7 +194,7 @@ export default function ({ contentsString }) {
<span className="inline-flex items-center text-sm"> <span className="inline-flex items-center text-sm">
<Link href={`/resources/${service.slug}`} passHref legacyBehavior> <Link href={`/resources/${service.slug}`} passHref legacyBehavior>
<a className="inline-flex space-x-2 text-gray-400 hover:text-gray-800"> <a className="inline-flex space-x-2 text-gray-400 hover:text-gray-800">
<span className="font-medium">Mehr</span> <span className="font-medium">{translate('resources.buttons.more')}</span>
<IconArrowBigRight <IconArrowBigRight
className="h-5 w-5" className="h-5 w-5"
aria-hidden="true" aria-hidden="true"
...@@ -212,7 +214,7 @@ export default function ({ contentsString }) { ...@@ -212,7 +214,7 @@ export default function ({ contentsString }) {
<div aria-labelledby={'service-add-on'}> <div aria-labelledby={'service-add-on'}>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="text-sm font-medium text-gray-900"> <p className="text-sm font-medium text-gray-900">
Dein zukünftiger Inhalt {translate('resources.headlines.futurecontent')}
</p> </p>
</div> </div>
<div className="mt-2 text-sm text-gray-700 space-y-4"> <div className="mt-2 text-sm text-gray-700 space-y-4">
...@@ -227,7 +229,7 @@ export default function ({ contentsString }) { ...@@ -227,7 +229,7 @@ export default function ({ contentsString }) {
data-base={`${encodeEmail('fit-connect@fitko.de')}`} data-base={`${encodeEmail('fit-connect@fitko.de')}`}
className="inline-flex space-x-2 text-gray-400 hover:text-gray-800" className="inline-flex space-x-2 text-gray-400 hover:text-gray-800"
> >
<span className="font-medium">Kontakt</span> <span className="font-medium">{translate('resources.buttons.contact')}</span>
<IconMail <IconMail
className="h-5 w-5" className="h-5 w-5"
aria-hidden="true" aria-hidden="true"
......
{
"landingpage": {
"headlines": {
"title1": "Das Föderale",
"title2": "Entwicklungsportal",
"aboutfep": "Über das Föderale Entwicklungsportal",
"feedback": "Du möchtest Fehler oder Verbesserungsvorschläge melden?",
"questions": "Du hast Fragen oder neue Ideen, die Du gerne diskutieren möchtest?",
"getstarted": "Direkt loslegen!",
"interfaces": "Standards und Schnittstellen",
"submissionapi": "Submission-API",
"routingapi": "Routing-API",
"legal": "RECHTLICHES"
},
"paragraphs": {
"title": "Willkommen im Föderalen Entwicklungsportal, dem zentralen Ort für technische Dokumentation, Entwicklungsressourcen und Implementierungsbeispiele zu Standards und Schnittstellen der föderalen IT-Infrastruktur von Bund und Ländern."
},
"links": {
"imprint": "Impressum",
"privacy": "Datenschutz*",
"accessibility": "Barrierefreiheit"
},
"buttons": {
"toresources": "Zu den Entwicklungsressourcen",
"learnmore": "Mehr erfahren"
}
},
"resources": {
"headlines": {
"title": "Verfügbare Plattformen & Basisdienste",
"resource": "ART DER RESSOURCE",
"status": "STATUS",
"futurecontent": "Dein zukünftiger Inhalt"
},
"buttons": {
"backhome": "Föderales Entwicklungsportal",
"more": "Mehr",
"toresource": "Direkt zur Ressource",
"contact": "Kontakt"
}
},
"resourcedetail": {
"labels": {
"responsible": "Verantwortlich",
"contact": "Kontakt",
"status": "Status",
"sourcecode": "Quellcode",
"resource": "Ressource",
"tosurl": "Nutzungsbedingungen",
"issueurl": "Nutzungsbedingungen"
},
"buttons": {
"toresource": "Zur Ressource",
"backtolist": "Zurück zur Übersicht"
}
}
}
import { ServiceContent } from 'types/ServiceContent'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { remark } from 'remark' import { remark } from 'remark'
import html from 'remark-html' import html from 'remark-html'
import { ChildResource, LabelTag, StatusTag, Tag, TypeTag } from 'types/content/' import { parse } from 'yaml'
import { ServiceContent } from 'types/ServiceContent'
import { LabelTag, StatusTag, Tag, TypeTag } from 'types/content/'
export default function loadAndPrepareMarkdown(selectedServiceName: string) { export default function loadAndPrepareMarkdown(selectedServiceName: string): ServiceContent {
const markdownFileContent: string = loadMarkdown(selectedServiceName) const markdownFileContent: string = loadMarkdown(selectedServiceName)
const content: ServiceContent = prepareContentFromMarkdown(markdownFileContent, selectedServiceName) const content: ServiceContent = prepareContentFromMarkdown(markdownFileContent, selectedServiceName)
return content return content
} }
function loadMarkdown(selectedServiceName: string) { function loadMarkdown(selectedServiceName: string): string {
const fullPath: string = path.join(process.cwd(), 'content', 'resources', `${selectedServiceName}`, `${selectedServiceName}.md`) const fullPath: string = path.join(process.cwd(), 'content', 'resources', `${selectedServiceName}`, `${selectedServiceName}.md`)
const markdownContent: string = fs.readFileSync(fullPath, 'utf8') const markdownContent: string = fs.readFileSync(fullPath, 'utf8')
return markdownContent return markdownContent
} }
function prepareContentFromMarkdown(markdownContent: string, selectedServiceName: string) { function prepareContentFromMarkdown(markdownContent: string, selectedServiceName: string): ServiceContent {
// eslint-disable-next-line no-unused-vars const [metadata, text] = markdownContent.split('---').slice(1)
const [header, metadata, text] = markdownContent.split('---')
const content: ServiceContent = parseMetadata(metadata) const content: ServiceContent = parseMetadata(metadata)
content.slug = selectedServiceName content.slug = selectedServiceName
content.text = parseTextToHTMLString(text) content.text = parseTextToHTMLString(text)
return content return content
} }
function parseTextToHTMLString(markdownText: string) { function parseTextToHTMLString(markdownText: string): string {
const sanitizedMarkdownText: string = sanitizeMarkdownText(markdownText) const sanitizedMarkdownText: string = sanitizeMarkdownText(markdownText)
const processedContent = remark().use(html).processSync(sanitizedMarkdownText) const processedContent = remark().use(html).processSync(sanitizedMarkdownText)
const htmlContent: string = processedContent.toString() const htmlContent: string = processedContent.toString()
...@@ -34,75 +34,16 @@ function parseTextToHTMLString(markdownText: string) { ...@@ -34,75 +34,16 @@ function parseTextToHTMLString(markdownText: string) {
} }
function parseMetadata(metadata: string): ServiceContent { function parseMetadata(metadata: string): ServiceContent {
const lines: string[] = metadata.split('\n') const contentData: any = parse(metadata)
const content: ServiceContent = new ServiceContent() const content: ServiceContent = new ServiceContent(contentData)
if (contentData.tags.length) {
let parentKey: string = '' content.tags = contentData.tags.map((tagData: any) => createTag(tagData))
}
lines.forEach((line: string) => { return content
// Skips empty line
if (line === '') {
return
}
// Current line is a key
if (line.endsWith(':')) {
// handels nested objects like contactInformation and developer
parentKey = line.slice(0, -1)
return
}
if (line.startsWith('shortDescription')) {
const [key, value] = convertLineIntoTuple(line)
content[key] = value
parentKey = key
return
}
// Current line is shortDescription text
if (parentKey === 'shortDescription' && startsWithTwoSpaces(line)) {
content.shortDescription = content.shortDescription + ' ' + line.trim()
return
}
// Convert line into tupel
const [key, value] = convertLineIntoTuple(line)
if (parentKey === 'childResources') {
if (key === '- name') {
content.childResources.push(new ChildResource({ name: value, slug: '' }))
return
}
content.childResources[content.childResources.length - 1].slug = value
return
}
// Check for explicit keys
if (parentKey === 'contactInformation' || parentKey === 'developer' || parentKey === 'logo') {
if (content[parentKey][key] === '') {
content[parentKey][key] = value
}
// check if contactInformation / developer are correctly assigned
if (content[parentKey].initialized) {
parentKey = ''
return
}
return
}
if (parentKey === 'tags') {
const tag: Tag | undefined = createTag(key, value)
if (tag) {
content[parentKey].push(tag)
}
return
}
// Assign simple key value tuple
content[key] = value
})
return new ServiceContent(content)
} }
function createTag(key: string, value: string) {
function createTag(tagData: string): Tag {
const [key, value] = tagData.split(':')
if (key.includes('type')) { if (key.includes('type')) {
return new TypeTag(value) return new TypeTag(value)
} else if (key.includes('status')) { } else if (key.includes('status')) {
...@@ -111,16 +52,7 @@ function createTag(key: string, value: string) { ...@@ -111,16 +52,7 @@ function createTag(key: string, value: string) {
return new LabelTag(value) return new LabelTag(value)
} }
} }
function convertLineIntoTuple(lineString: string) {
const trimmedLine: string = lineString.trim() function sanitizeMarkdownText(markdownText: string): string {
const [key, value] = trimmedLine.split(/:(.*)/s)
const trimmedValue = value?.trim()
return [key, trimmedValue]
}
function startsWithTwoSpaces(stringToCheck: string) {
return /^\s{2}/.test(stringToCheck)
}
function sanitizeMarkdownText(markdownText: string) {
// trim whitespaces; replace line breaks with and remove multiple whitespaces
return markdownText.trim().replace(/ +(?= )/g, ' ') return markdownText.trim().replace(/ +(?= )/g, ' ')
} }
import translations from '../public/locales/de/common.json'
const useTranslation = () => {
const translate = (translationKey: any): string => {
const keys = translationKey.split('.')
let translation: any = translations
for (const key of keys) {
translation = translation?.[key] ?? translationKey
}
if (translation == translationKey) {
console.log(`Warning: i18n - Translation ${translationKey} not found.`)
}
return translation
}
return { translate }
}
export default useTranslation
...@@ -57,6 +57,16 @@ const blogEntries = ...@@ -57,6 +57,16 @@ const blogEntries =
icon: IconBrandOpenSource, icon: IconBrandOpenSource,
text: 'Im <a href=\'https://discourse.opencode.de/\'>Forum des Open Source Code Repository</a> ist Platz dafür. Wir freuen uns auf Deinen Beitrag!', text: 'Im <a href=\'https://discourse.opencode.de/\'>Forum des Open Source Code Repository</a> ist Platz dafür. Wir freuen uns auf Deinen Beitrag!',
}, },
{
headline: 'Direkt loslegen!',
icon: IconRocket,
text: 'Mit den folgenden Ressourcen kannst Du direkt loslegen und mehr über die Föderale IT-Infrastruktur von Bund und Ländern erfahren und Anwendungen für die Öffentliche Verwaltung erstellen. Pespektivisch werden an dieser Stelle konkrete Entwicklungsszenarien mit den jeweils dafür benötigten Entwicklungsressourcen zusammengestellt.',
link: {
href: '/resources',
text: 'Zu den Entwicklungsressourcen',
icon: IconArrowBigRight,
},
},
] ]
export default () => { export default () => {
...@@ -83,35 +93,21 @@ export default () => { ...@@ -83,35 +93,21 @@ export default () => {
</h1> </h1>
</div> </div>
<p className="cms-blog-text p-8 mt-6 max-w-7xl text-lg text-gray-800 bg-white rounded-2xl" dangerouslySetInnerHTML={{ __html: blogEntry.text }} /> <p className="cms-blog-text p-8 mt-6 max-w-7xl text-lg text-gray-800 bg-white rounded-2xl" dangerouslySetInnerHTML={{ __html: blogEntry.text }} />
{blogEntry?.link &&
<div className="p-6 -mt-4 bg-gray-50 rounded-bl-2xl rounded-br-2xl md:px-8 flex">
<Link href={ blogEntry.link.href } passHref legacyBehavior>
<a className="justify-start text-base text-yellow-400 hover:text-yellow-600 inline-flex space-x-2">
<span className="font-bold xl:py-0.5">{ blogEntry.link.text }</span>
<blogEntry.link.icon
className="h-7 w-7 xl:py-1"
aria-hidden="true"
/>
</a>
</Link>
</div>
}
</section> </section>
))} ))}
<section className="relative max-w-7xl mx-auto pt-14 pb-24 px-4 sm:px-6 lg:px-8">
<div className='flex justify-start'>
<div className="h-16 w-16 m-2.5 p-5 bg-yellow-400 rounded-xl shadow-lg">
<IconRocket
className="h-6 w-6 text-white"
/>
</div>
<h1 className="overflow-hidden py-1 sm:py-0.5 m-4 text-2xl sm:text-3xl tracking-tight text-white drop-shadow-md">
Direkt loslegen!
</h1>
</div>
<p className="p-8 mt-6 max-w-7xl text-lg text-gray-800 bg-white rounded-t-2xl">
Mit den folgenden Ressourcen kannst Du direkt loslegen und mehr über die Föderale IT-Infrastruktur von Bund und Ländern erfahren und Anwendungen für die Öffentliche Verwaltung erstellen. Pespektivisch werden an dieser Stelle konkrete Entwicklungsszenarien mit den jeweils dafür benötigten Entwicklungsressourcen zusammengestellt.
</p>
<div className="p-6 bg-gray-50 rounded-bl-2xl rounded-br-2xl md:px-8 flex">
<Link href="/resources" passHref legacyBehavior>
<a className="justify-start text-base text-yellow-400 hover:text-yellow-600 inline-flex space-x-2">
<span className="font-bold xl:py-0.5">Zu den Entwicklungsressourcen</span>
<IconArrowBigRight
className="h-7 w-7 xl:py-1"
aria-hidden="true"
/>
</a>
</Link>
</div>
</section>
</div> </div>
{/* Overlapping cards */} {/* Overlapping cards */}
......
import Link from 'next/link' import Link from 'next/link'
import useBasePath from '../shared/use-base-path' import useBasePath from '../shared/use-base-path'
import useTranslation from '../shared/use-translation'
export default () => { export default () => {
const basePath = useBasePath() const basePath = useBasePath()
const { translate } = useTranslation()
return ( return (
<div className="relative bg-white overflow-hidden"> <div className="relative bg-white overflow-hidden">
...@@ -12,19 +14,17 @@ export default () => { ...@@ -12,19 +14,17 @@ export default () => {
<div className="sm:text-center md:max-w-4xl md:mx-auto lg:col-span-8 lg:text-left"> <div className="sm:text-center md:max-w-4xl md:mx-auto lg:col-span-8 lg:text-left">
<h1 className="xl:pb-1"> <h1 className="xl:pb-1">
<span className="mt-1 block text-3xl tracking-tight sm:text-5xl xl:text-7xl"> <span className="mt-1 block text-3xl tracking-tight sm:text-5xl xl:text-7xl">
<span className="block text-gray-900">Das Föderale</span> <span className="block text-gray-900">{ translate('landingpage.headlines.title1') }</span>
<span className="block text-yellow-400"> <span className="block text-yellow-400">{ translate('landingpage.headlines.title2') }</span>
Entwicklungsportal
</span>
</span> </span>
</h1> </h1>
<p className="mt-3 text-base text-gray-500 sm:mt-5 sm:text-xl lg:text-lg xl:text-2xl"> <p className="mt-3 text-base text-gray-500 sm:mt-5 sm:text-xl lg:text-lg xl:text-2xl">
Willkommen im Föderalen Entwicklungsportal, dem zentralen Ort für technische Dokumentation, Entwicklungsressourcen und Implementierungsbeispiele zu Standards und Schnittstellen der föderalen IT-Infrastruktur von Bund und Ländern. { translate('landingpage.paragraphs.title') }
</p> </p>
<div className="mt-8 lg:mxw-0 flex items-stretch grow lg:w-2/3"> <div className="mt-8 lg:mxw-0 flex items-stretch grow lg:w-2/3">
<Link href="/resources" passHref legacyBehavior> <Link href="/resources" passHref legacyBehavior>
<a className="justify-center text-lg -ml-px relative inline-flex space-x-2 px-4 py-2 font-medium rounded-md text-white bg-yellow-400 hover:bg-yellow-300 hover:cursor-pointer shadow-sm w-full"> <a className="justify-center text-lg -ml-px relative inline-flex space-x-2 px-4 py-2 font-medium rounded-md text-white bg-yellow-400 hover:bg-yellow-300 hover:cursor-pointer shadow-sm w-full">
Zu den Entwicklungsressourcen { translate('landingpage.buttons.toresources') }
</a> </a>
</Link> </Link>
</div> </div>
......
import React from 'react' import React from 'react'
import Link from 'next/link' import Link from 'next/link'
import PageHeaderCard from '@/components/PageHeaderCard' import PageHeaderCard from '@/components/PageHeaderCard'
import { decodeEmail } from '@/lib/utils' import useTranslation from '../shared/use-translation'
type HeaderOptions = { type HeaderOptions = {
title: string title: string
...@@ -39,11 +39,12 @@ export function Header({ ...@@ -39,11 +39,12 @@ export function Header({
issuesURL, issuesURL,
resources, resources,
}: HeaderOptions) { }: HeaderOptions) {
const { translate } = useTranslation()
return ( return (
<PageHeaderCard title={title} description={description} img={img}> <PageHeaderCard title={title} description={description} img={img}>
{developer && ( {developer && (
<div className="sm:col-span-1 text-left"> <div className="sm:col-span-1 text-left">
<dt className="text-sm font-medium text-gray-500">Verantwortlich</dt> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.responsible') }</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={developer.link} target={'_blank'}> <a href={developer.link} target={'_blank'}>
{developer.name} {developer.name}
...@@ -53,7 +54,7 @@ export function Header({ ...@@ -53,7 +54,7 @@ export function Header({
)} )}
{contact && ( {contact && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500">Kontakt</dt> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.contact') }</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a <a
target={'_blank'} target={'_blank'}
...@@ -69,7 +70,7 @@ export function Header({ ...@@ -69,7 +70,7 @@ export function Header({
)} )}
{statusLabel && ( {statusLabel && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500">Status</dt> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.status') }</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900"> <dd className="ml-0 mt-1 text-sm text-gray-900">
{statusLabel} {statusLabel}
</dd> </dd>
...@@ -77,7 +78,7 @@ export function Header({ ...@@ -77,7 +78,7 @@ export function Header({
)} )}
{sourceURL && ( {sourceURL && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500">Quellcode</dt> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.sourcecode') }</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={sourceURL} target={'_blank'}> <a href={sourceURL} target={'_blank'}>
{sourceURL} {sourceURL}
...@@ -87,7 +88,7 @@ export function Header({ ...@@ -87,7 +88,7 @@ export function Header({
)} )}
{resources.length > 0 && ( {resources.length > 0 && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500">Ressourcen</dt> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.resource') }</dt>
{resources.map((resource, index) => ( {resources.map((resource, index) => (
<dd key={index} className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd key={index} className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
...@@ -103,9 +104,7 @@ export function Header({ ...@@ -103,9 +104,7 @@ export function Header({
)} )}
{tosURL && ( {tosURL && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500"> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.tosurl') }</dt>
Nutzungsbedingungen
</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={tosURL} target={'_blank'}> <a href={tosURL} target={'_blank'}>
{tosURL} {tosURL}
...@@ -115,9 +114,7 @@ export function Header({ ...@@ -115,9 +114,7 @@ export function Header({
)} )}
{issuesURL && ( {issuesURL && (
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500"> <dt className="text-sm font-medium text-gray-500">{ translate('resourcedetail.labels.issueurl') }</dt>
Nutzungsbedingungen
</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={issuesURL} target={'_blank'}> <a href={issuesURL} target={'_blank'}>
{issuesURL} {issuesURL}
...@@ -129,7 +126,7 @@ export function Header({ ...@@ -129,7 +126,7 @@ export function Header({
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<div className="sm:text-center sm:max-w-lg lg:mxw-0 flex items-stretch flex-grow"> <div className="sm:text-center sm:max-w-lg lg:mxw-0 flex items-stretch flex-grow">
<a className="text-center text-lg relative inline-flex space-x-2 px-4 py-2 font-medium rounded-md text-white bg-yellow-400 hover:bg-yellow-300 hover:cursor-pointer shadow-sm" href={documentationURL}> <a className="text-center text-lg relative inline-flex space-x-2 px-4 py-2 font-medium rounded-md text-white bg-yellow-400 hover:bg-yellow-300 hover:cursor-pointer shadow-sm" href={documentationURL}>
Zur Ressource { translate('resourcedetail.buttons.toresource') }
</a> </a>
</div> </div>
</div> </div>
......
...@@ -20,47 +20,47 @@ type HeaderOptions = { ...@@ -20,47 +20,47 @@ type HeaderOptions = {
} }
export function Header({ export function Header({
title, title,
description, description,
img, img,
owner, owner,
manager, manager,
website, website,
}: HeaderOptions) { }: HeaderOptions) {
return ( return (
<PageHeaderCard title={title} description={description} img={img}> <PageHeaderCard title={title} description={description} img={img}>
<div className="sm:col-span-1 text-left"> <div className="sm:col-span-1 text-left">
<dt className="text-sm font-medium text-gray-500">Betreiber</dt> <dt className="text-sm font-medium text-gray-500">Betreiber</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={owner.link} target={'_blank'}> <a href={owner.link} target={'_blank'}>
{owner.name} {owner.name}
</a> </a>
</dd> </dd>
</div> </div>
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500"> <dt className="text-sm font-medium text-gray-500">
Kontakt Kontakt
</dt> </dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a <a
target={'_blank'} target={'_blank'}
onClick={(e) => { onClick={(e) => {
window.open(`mailto:${decodeEmail(manager.mailTo)}`, '_blank') window.open(`mailto:${decodeEmail(manager.mailTo)}`, '_blank')
e.preventDefault() e.preventDefault()
}} }}
> >
{manager.name ? manager.name : decodeEmail(manager.mailTo).replace('@', '<ät>')} {manager.name ? manager.name : decodeEmail(manager.mailTo).replace('@', '<ät>')}
</a> </a>
</dd> </dd>
</div> </div>
<div className="sm:col-span-1"> <div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500">Webseite</dt> <dt className="text-sm font-medium text-gray-500">Webseite</dt>
<dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer"> <dd className="ml-0 mt-1 text-sm text-gray-900 hover:cursor-pointer">
<a href={website} target={'_blank'}> <a href={website} target={'_blank'}>
{website} {website}
</a> </a>
</dd> </dd>
</div> </div>
</PageHeaderCard> </PageHeaderCard>
) )
} }
...@@ -3647,7 +3647,7 @@ yallist@^4.0.0: ...@@ -3647,7 +3647,7 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^2.1.1: yaml@^2.1.1, yaml@^2.3.2:
version "2.3.2" version "2.3.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144"
integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==
......