mirror of
https://github.com/kevinveenbirkenbach/homepage.veen.world.git
synced 2025-01-15 19:23:58 +01:00
Refactored code and implemented new childrens loading
This commit is contained in:
parent
c01e9125aa
commit
9ff356ba70
505
app/config.yaml
505
app/config.yaml
@ -4,12 +4,12 @@ accounts:
|
|||||||
description: My Online Accounts
|
description: My Online Accounts
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-users
|
class: fa-solid fa-users
|
||||||
subitems:
|
children:
|
||||||
- name: Publications
|
- name: Publications
|
||||||
description: My Publications
|
description: My Publications
|
||||||
icon:
|
icon:
|
||||||
class: fas fa-newspaper
|
class: fas fa-newspaper
|
||||||
subitems:
|
children:
|
||||||
- name: Microblog
|
- name: Microblog
|
||||||
description: Read my microblogs
|
description: Read my microblogs
|
||||||
icon:
|
icon:
|
||||||
@ -19,7 +19,7 @@ accounts:
|
|||||||
- name: Pictures
|
- name: Pictures
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-images
|
class: fa-solid fa-images
|
||||||
subitems:
|
children:
|
||||||
- name: Pixelfed
|
- name: Pixelfed
|
||||||
description: View my photo gallery
|
description: View my photo gallery
|
||||||
icon:
|
icon:
|
||||||
@ -49,7 +49,7 @@ accounts:
|
|||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-laptop-code
|
class: fa-solid fa-laptop-code
|
||||||
description: Check out my Code
|
description: Check out my Code
|
||||||
subitems:
|
children:
|
||||||
- name: Github
|
- name: Github
|
||||||
description: View my GitHub profile
|
description: View my GitHub profile
|
||||||
icon:
|
icon:
|
||||||
@ -66,7 +66,7 @@ accounts:
|
|||||||
icon:
|
icon:
|
||||||
class: fa-brands fa-meta
|
class: fa-brands fa-meta
|
||||||
url:
|
url:
|
||||||
subitems:
|
children:
|
||||||
- name: Facebook
|
- name: Facebook
|
||||||
description: Like my Facebook page
|
description: Like my Facebook page
|
||||||
icon:
|
icon:
|
||||||
@ -76,7 +76,7 @@ accounts:
|
|||||||
- name: Carreer Profiles
|
- name: Carreer Profiles
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-user-tie
|
class: fa-solid fa-user-tie
|
||||||
subitems:
|
children:
|
||||||
- name: XING
|
- name: XING
|
||||||
description: Visit my XING profile
|
description: Visit my XING profile
|
||||||
icon:
|
icon:
|
||||||
@ -94,7 +94,7 @@ accounts:
|
|||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-running
|
class: fa-solid fa-running
|
||||||
url:
|
url:
|
||||||
subitems:
|
children:
|
||||||
- name: Garmin
|
- name: Garmin
|
||||||
description: My Garmin activities
|
description: My Garmin activities
|
||||||
icon:
|
icon:
|
||||||
@ -250,263 +250,266 @@ company:
|
|||||||
country: Germany
|
country: Germany
|
||||||
imprint_url: https://s.veen.world/imprint
|
imprint_url: https://s.veen.world/imprint
|
||||||
navigation:
|
navigation:
|
||||||
header:
|
header:
|
||||||
- name: Contact
|
children:
|
||||||
description: Get in touch
|
- link: accounts.publications.children
|
||||||
icon:
|
- name: Contact
|
||||||
class: fa-solid fa-envelope
|
description: Get in touch
|
||||||
subitems:
|
|
||||||
- name: Email
|
|
||||||
description: Send me an email
|
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-envelope
|
class: fa-solid fa-envelope
|
||||||
subitems:
|
children:
|
||||||
- name: Email
|
- name: Email
|
||||||
description: Send me an email
|
description: Send me an email
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-envelope
|
class: fa-solid fa-envelope
|
||||||
url: mailto:kevin@veen.world
|
children:
|
||||||
identifier: kevin@veen.world
|
- name: Email
|
||||||
alternatives:
|
description: Send me an email
|
||||||
- link: navigation.header.contact.messenger.matrix
|
icon:
|
||||||
- name: Encrypted Email (PGP)
|
class: fa-solid fa-envelope
|
||||||
description: Download my PGP key
|
url: mailto:kevin@veen.world
|
||||||
|
identifier: kevin@veen.world
|
||||||
|
alternatives:
|
||||||
|
- link: navigation.header.contact.messenger.matrix
|
||||||
|
- name: Encrypted Email (PGP)
|
||||||
|
description: Download my PGP key
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-key
|
||||||
|
url: https://s.veen.world/pgp
|
||||||
|
identifier: kevin@veen.world
|
||||||
|
info: |
|
||||||
|
#### Why Use PGP?
|
||||||
|
PGP ensures your email content stays private, protecting against surveillance, data breaches, and unauthorized access.
|
||||||
|
|
||||||
|
#### Protect Your Privacy
|
||||||
|
In an age of mass data collection, PGP empowers you to communicate securely and assert control over your information. For insights on protecting your digital rights, visit the [Electronic Frontier Foundation (EFF)](https://www.eff.org/).
|
||||||
|
|
||||||
|
#### Build Trust
|
||||||
|
Encrypting emails demonstrates a commitment to privacy and security, fostering trust in professional and personal communication.
|
||||||
|
|
||||||
|
#### Stand for Security
|
||||||
|
Using PGP is more than a tool—it's a statement about valuing freedom, privacy, and the security of digital communication. Explore the principles of secure communication with [privacy guides](https://privacyguides.org/).
|
||||||
|
- name: Mobile
|
||||||
|
description: Call me
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-key
|
class: fa-solid fa-phone
|
||||||
url: https://s.veen.world/pgp
|
url: "tel:+491781798023"
|
||||||
identifier: kevin@veen.world
|
|
||||||
info: |
|
|
||||||
#### Why Use PGP?
|
|
||||||
PGP ensures your email content stays private, protecting against surveillance, data breaches, and unauthorized access.
|
|
||||||
|
|
||||||
#### Protect Your Privacy
|
|
||||||
In an age of mass data collection, PGP empowers you to communicate securely and assert control over your information. For insights on protecting your digital rights, visit the [Electronic Frontier Foundation (EFF)](https://www.eff.org/).
|
|
||||||
|
|
||||||
#### Build Trust
|
|
||||||
Encrypting emails demonstrates a commitment to privacy and security, fostering trust in professional and personal communication.
|
|
||||||
|
|
||||||
#### Stand for Security
|
|
||||||
Using PGP is more than a tool—it's a statement about valuing freedom, privacy, and the security of digital communication. Explore the principles of secure communication with [privacy guides](https://privacyguides.org/).
|
|
||||||
- name: Mobile
|
|
||||||
description: Call me
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-phone
|
|
||||||
url: "tel:+491781798023"
|
|
||||||
identifier: "+491781798023"
|
|
||||||
target: _top
|
|
||||||
- name: Messenger
|
|
||||||
description: Social and developer networks
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-comments
|
|
||||||
subitems:
|
|
||||||
- name: Matrix
|
|
||||||
description: Chat with me on Matrix
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-cubes
|
|
||||||
identifier: "@kevinveenbirkenbach:veen.world"
|
|
||||||
info: |
|
|
||||||
#### Why Use Matrix?
|
|
||||||
Matrix is a secure, decentralized communication platform that ensures privacy and control over your data. Learn more about [Matrix](https://matrix.org/).
|
|
||||||
|
|
||||||
#### Privacy and Security
|
|
||||||
End-to-end encryption keeps your conversations private and secure.
|
|
||||||
|
|
||||||
#### Decentralized and Open
|
|
||||||
Matrix's federated network means you can host your own server or use any provider while staying connected.
|
|
||||||
|
|
||||||
#### A Movement for Digital Freedom
|
|
||||||
By using Matrix, you support open, transparent, and secure communication.
|
|
||||||
- name: Signal
|
|
||||||
description: Message me on Signal
|
|
||||||
icon:
|
|
||||||
class: fa-brands fa-signal-messenger
|
|
||||||
identifier: "+491781798023"
|
identifier: "+491781798023"
|
||||||
warning: Signal is not hosted by me!
|
target: _top
|
||||||
alternatives:
|
- name: Messenger
|
||||||
- link: navigation.header.contact.messenger.matrix
|
description: Social and developer networks
|
||||||
- name: Telegram
|
|
||||||
description: Message me on Telegram
|
|
||||||
icon:
|
icon:
|
||||||
class: fa-brands fa-telegram
|
class: fa-solid fa-comments
|
||||||
target: _blank
|
children:
|
||||||
url: https://t.me/kevinveenbirkenbach
|
- name: Matrix
|
||||||
identifier: kevinveenbirkenbach
|
description: Chat with me on Matrix
|
||||||
warning: Telegram is not hosted by me!
|
icon:
|
||||||
alternatives:
|
class: fa-solid fa-cubes
|
||||||
- link: navigation.header.contact.messenger.matrix
|
identifier: "@kevinveenbirkenbach:veen.world"
|
||||||
- name: WhatsApp
|
info: |
|
||||||
description: Chat with me on WhatsApp
|
#### Why Use Matrix?
|
||||||
icon:
|
Matrix is a secure, decentralized communication platform that ensures privacy and control over your data. Learn more about [Matrix](https://matrix.org/).
|
||||||
class: fa-brands fa-whatsapp
|
|
||||||
url: https://wa.me/491781798023
|
|
||||||
identifier: "+491781798023"
|
|
||||||
info: Consider using decentralized and privacy-respecting alternatives to maintain control over your data, improve security, and foster healthier online interactions.
|
|
||||||
alternatives:
|
|
||||||
- link: navigation.header.contact.messenger.matrix
|
|
||||||
- link: navigation.header.contact.messenger.signal
|
|
||||||
- link: navigation.header.contact.messenger.telegram
|
|
||||||
|
|
||||||
|
#### Privacy and Security
|
||||||
|
End-to-end encryption keeps your conversations private and secure.
|
||||||
|
|
||||||
|
#### Decentralized and Open
|
||||||
|
Matrix's federated network means you can host your own server or use any provider while staying connected.
|
||||||
|
|
||||||
|
#### A Movement for Digital Freedom
|
||||||
|
By using Matrix, you support open, transparent, and secure communication.
|
||||||
|
- name: Signal
|
||||||
|
description: Message me on Signal
|
||||||
|
icon:
|
||||||
|
class: fa-brands fa-signal-messenger
|
||||||
|
identifier: "+491781798023"
|
||||||
|
warning: Signal is not hosted by me!
|
||||||
|
alternatives:
|
||||||
|
- link: navigation.header.contact.messenger.matrix
|
||||||
|
- name: Telegram
|
||||||
|
description: Message me on Telegram
|
||||||
|
icon:
|
||||||
|
class: fa-brands fa-telegram
|
||||||
|
target: _blank
|
||||||
|
url: https://t.me/kevinveenbirkenbach
|
||||||
|
identifier: kevinveenbirkenbach
|
||||||
|
warning: Telegram is not hosted by me!
|
||||||
|
alternatives:
|
||||||
|
- link: navigation.header.contact.messenger.matrix
|
||||||
|
- name: WhatsApp
|
||||||
|
description: Chat with me on WhatsApp
|
||||||
|
icon:
|
||||||
|
class: fa-brands fa-whatsapp
|
||||||
|
url: https://wa.me/491781798023
|
||||||
|
identifier: "+491781798023"
|
||||||
|
info: Consider using decentralized and privacy-respecting alternatives to maintain control over your data, improve security, and foster healthier online interactions.
|
||||||
|
alternatives:
|
||||||
|
- link: navigation.header.contact.messenger.matrix
|
||||||
|
- link: navigation.header.contact.messenger.signal
|
||||||
|
- link: navigation.header.contact.messenger.telegram
|
||||||
footer:
|
footer:
|
||||||
- link: accounts
|
children:
|
||||||
- name: Solution Hub
|
- link: accounts
|
||||||
description: Curated collection of self hosted tools
|
- name: Solution Hub
|
||||||
icon:
|
description: Curated collection of self hosted tools
|
||||||
class: fa-solid fa-network-wired
|
|
||||||
url:
|
|
||||||
subitems:
|
|
||||||
- name: Community
|
|
||||||
description: Tools to manage the community
|
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-users
|
class: fa-solid fa-network-wired
|
||||||
subitems:
|
url:
|
||||||
- name: Forum
|
children:
|
||||||
description: Join the discussion
|
- name: Community
|
||||||
|
description: Tools to manage the community
|
||||||
icon:
|
icon:
|
||||||
class: fa-brands fa-discourse
|
class: fa-solid fa-users
|
||||||
url: https://forum.veen.world/
|
children:
|
||||||
- name: Learning Platform
|
- name: Forum
|
||||||
description: Learn with my academy
|
description: Join the discussion
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-graduation-cap
|
class: fa-brands fa-discourse
|
||||||
url: https://academy.veen.world/
|
url: https://forum.veen.world/
|
||||||
- name: Newsletter
|
- name: Learning Platform
|
||||||
description: Subscribe to my newsletter
|
description: Learn with my academy
|
||||||
icon:
|
|
||||||
class: fa-solid fa-envelope-open-text
|
|
||||||
url: https://newsletter.veen.world/subscription/form
|
|
||||||
- name: Project Management
|
|
||||||
description: Project Management Tools
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-chart-line
|
|
||||||
subitems:
|
|
||||||
- name: Open Project
|
|
||||||
description: Explore my projects
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-tasks
|
|
||||||
url: https://project.veen.world/
|
|
||||||
|
|
||||||
- name: Taiga
|
|
||||||
description: View my Kanban board
|
|
||||||
icon:
|
|
||||||
class: bi bi-clipboard2-check-fill
|
|
||||||
url: https://kanban.veen.world/
|
|
||||||
|
|
||||||
- name: Communication
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-comments
|
|
||||||
subitems:
|
|
||||||
- name: Elements
|
|
||||||
description: Chat with me
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-comment
|
|
||||||
url: https://element.veen.world/
|
|
||||||
|
|
||||||
- name: Big Blue Button
|
|
||||||
description: Join live events
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-video
|
|
||||||
url: https://meet.veen.world/
|
|
||||||
|
|
||||||
- name: Mailu
|
|
||||||
description: Send me a mail
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-envelope
|
|
||||||
url: https://mail.veen.world/
|
|
||||||
- name: Tools
|
|
||||||
icon:
|
|
||||||
class: fas fa-tools
|
|
||||||
subitems:
|
|
||||||
- name: Matomo
|
|
||||||
description: Analyze with Matomo
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-chart-simple
|
|
||||||
url: https://matomo.veen.world/
|
|
||||||
|
|
||||||
- name: Baserow
|
|
||||||
description: Organize with Baserow
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-table
|
|
||||||
url: https://baserow.veen.world/
|
|
||||||
- name: Yourls
|
|
||||||
description: Find my curated links
|
|
||||||
icon:
|
|
||||||
class: bi bi-link
|
|
||||||
url: https://s.veen.world/admin/
|
|
||||||
|
|
||||||
- name: Nextcloud
|
|
||||||
description: Access my cloud storage
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-cloud
|
|
||||||
url: https://cloud.veen.world/
|
|
||||||
|
|
||||||
- name: About
|
|
||||||
description: All information about me
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-user
|
|
||||||
subitems:
|
|
||||||
- name: Logbooks
|
|
||||||
description: Access my personal logbooks (diving, flying, sailing)
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-book
|
|
||||||
subitems:
|
|
||||||
- name: Skydiver
|
|
||||||
description: View my skydiving logs
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-parachute-box
|
|
||||||
url: https://s.veen.world/skydiverlog
|
|
||||||
|
|
||||||
- name: Skipper
|
|
||||||
description: See my sailing records
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-sailboat
|
|
||||||
url: https://s.veen.world/meilenbuch
|
|
||||||
|
|
||||||
- name: Diver
|
|
||||||
description: Check my diving logs
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-fish
|
|
||||||
url: https://s.veen.world/diverlog
|
|
||||||
|
|
||||||
- name: Pilot
|
|
||||||
description: Review my flight logs
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-plane
|
|
||||||
url: https://s.veen.world/pilotlog
|
|
||||||
|
|
||||||
- name: Nature
|
|
||||||
description: Explore my nature logs
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-tree
|
|
||||||
url: https://s.veen.world/naturejournal
|
|
||||||
- name: Vita
|
|
||||||
description: View my CV
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-file-lines
|
|
||||||
url: https://s.veen.world/lebenslauf
|
|
||||||
- name: Credentials
|
|
||||||
description: Access my certifications, degrees, and professional records
|
|
||||||
icon:
|
|
||||||
class: fa-solid fa-id-card
|
|
||||||
subitems:
|
|
||||||
- name: Degrees
|
|
||||||
description: View my academic degrees
|
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-graduation-cap
|
class: fa-solid fa-graduation-cap
|
||||||
url: https://s.veen.world/degrees
|
url: https://academy.veen.world/
|
||||||
- name: Certificates
|
- name: Newsletter
|
||||||
description: View my training and professional development records
|
description: Subscribe to my newsletter
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-certificate
|
class: fa-solid fa-envelope-open-text
|
||||||
url: https://s.veen.world/certificates
|
url: https://newsletter.veen.world/subscription/form
|
||||||
- name: Certifications
|
- name: Project Management
|
||||||
description: Browse all my certifications
|
description: Project Management Tools
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-chart-line
|
||||||
|
children:
|
||||||
|
- name: Open Project
|
||||||
|
description: Explore my projects
|
||||||
icon:
|
icon:
|
||||||
class: fa-solid fa-scroll
|
class: fa-solid fa-tasks
|
||||||
url: https://s.veen.world/certifications
|
url: https://project.veen.world/
|
||||||
- link: accounts
|
|
||||||
|
- name: Taiga
|
||||||
- name: Imprint
|
description: View my Kanban board
|
||||||
description: Check out the imprint information
|
icon:
|
||||||
icon:
|
class: bi bi-clipboard2-check-fill
|
||||||
class: fa-solid fa-scale-balanced
|
url: https://kanban.veen.world/
|
||||||
url: https://s.veen.world/imprint
|
|
||||||
|
- name: Communication
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-comments
|
||||||
|
children:
|
||||||
|
- name: Elements
|
||||||
|
description: Chat with me
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-comment
|
||||||
|
url: https://element.veen.world/
|
||||||
|
|
||||||
|
- name: Big Blue Button
|
||||||
|
description: Join live events
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-video
|
||||||
|
url: https://meet.veen.world/
|
||||||
|
|
||||||
|
- name: Mailu
|
||||||
|
description: Send me a mail
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-envelope
|
||||||
|
url: https://mail.veen.world/
|
||||||
|
- name: Tools
|
||||||
|
icon:
|
||||||
|
class: fas fa-tools
|
||||||
|
children:
|
||||||
|
- name: Matomo
|
||||||
|
description: Analyze with Matomo
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-chart-simple
|
||||||
|
url: https://matomo.veen.world/
|
||||||
|
|
||||||
|
- name: Baserow
|
||||||
|
description: Organize with Baserow
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-table
|
||||||
|
url: https://baserow.veen.world/
|
||||||
|
- name: Yourls
|
||||||
|
description: Find my curated links
|
||||||
|
icon:
|
||||||
|
class: bi bi-link
|
||||||
|
url: https://s.veen.world/admin/
|
||||||
|
|
||||||
|
- name: Nextcloud
|
||||||
|
description: Access my cloud storage
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-cloud
|
||||||
|
url: https://cloud.veen.world/
|
||||||
|
|
||||||
|
- name: About
|
||||||
|
description: All information about me
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-user
|
||||||
|
children:
|
||||||
|
- name: Logbooks
|
||||||
|
description: Access my personal logbooks (diving, flying, sailing)
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-book
|
||||||
|
children:
|
||||||
|
- name: Skydiver
|
||||||
|
description: View my skydiving logs
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-parachute-box
|
||||||
|
url: https://s.veen.world/skydiverlog
|
||||||
|
|
||||||
|
- name: Skipper
|
||||||
|
description: See my sailing records
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-sailboat
|
||||||
|
url: https://s.veen.world/meilenbuch
|
||||||
|
|
||||||
|
- name: Diver
|
||||||
|
description: Check my diving logs
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-fish
|
||||||
|
url: https://s.veen.world/diverlog
|
||||||
|
|
||||||
|
- name: Pilot
|
||||||
|
description: Review my flight logs
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-plane
|
||||||
|
url: https://s.veen.world/pilotlog
|
||||||
|
|
||||||
|
- name: Nature
|
||||||
|
description: Explore my nature logs
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-tree
|
||||||
|
url: https://s.veen.world/naturejournal
|
||||||
|
- name: Vita
|
||||||
|
description: View my CV
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-file-lines
|
||||||
|
url: https://s.veen.world/lebenslauf
|
||||||
|
- link: accounts
|
||||||
|
- name: Credentials
|
||||||
|
description: Access my certifications, degrees, and professional records
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-id-card
|
||||||
|
children:
|
||||||
|
- name: Degrees
|
||||||
|
description: View my academic degrees
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-graduation-cap
|
||||||
|
url: https://s.veen.world/degrees
|
||||||
|
- name: Certificates
|
||||||
|
description: View my training and professional development records
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-certificate
|
||||||
|
url: https://s.veen.world/certificates
|
||||||
|
- name: Certifications
|
||||||
|
description: Browse all my certifications
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-scroll
|
||||||
|
url: https://s.veen.world/certifications
|
||||||
|
|
||||||
|
- name: Imprint
|
||||||
|
description: Check out the imprint information
|
||||||
|
icon:
|
||||||
|
class: fa-solid fa-scale-balanced
|
||||||
|
url: https://s.veen.world/imprint
|
||||||
|
|
@ -1,33 +1,33 @@
|
|||||||
<!-- Template for Subitems -->
|
{% macro render_icon_and_name(item) %}
|
||||||
{% macro render_subitems(subitems) %}
|
<i class="{{ item.icon.class if item.icon is defined and item.icon.class is defined else 'fa-solid fa-link' }}"></i>
|
||||||
{% for subitem in subitems %}
|
{% if item.name is defined %}
|
||||||
{% if subitem.subitems %}
|
{{ item.name }}
|
||||||
|
{% else %}
|
||||||
|
Unnamed Item: {{item}}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
<!-- Template for children -->
|
||||||
|
{% macro render_children(children) %}
|
||||||
|
{% for children in children %}
|
||||||
|
{% if children.children %}
|
||||||
<li class="dropdown-submenu position-relative">
|
<li class="dropdown-submenu position-relative">
|
||||||
<a class="dropdown-item dropdown-toggle" href="#" title="{{ subitem.description }}">
|
<a class="dropdown-item dropdown-toggle" href="#" title="{{ children.description }}">
|
||||||
{% if subitem.icon is defined and subitem.icon.class is defined %}
|
{{ render_icon_and_name(children) }}
|
||||||
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
|
|
||||||
{% else %}
|
|
||||||
<p>Missing icon in subitem: {{ subitem }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{{ render_subitems(subitem.subitems) }}
|
{{ render_children(children.children) }}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% elif subitem.identifier or subitem.warning or subitem.info %}
|
{% elif children.identifier or children.warning or children.info %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" onclick='openDynamicPopup({{ subitem|tojson|safe }})' data-bs-toggle="tooltip" title="{{ subitem.description }}">
|
<a class="dropdown-item" onclick='openDynamicPopup({{ children|tojson|safe }})' data-bs-toggle="tooltip" title="{{ children.description }}">
|
||||||
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
|
{{ render_icon_and_name(children) }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="{{ subitem.url }}" target="{{ subitem.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ subitem.description }}">
|
<a class="dropdown-item" href="{{ children.url }}" target="{{ children.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ children.description }}">
|
||||||
{% if subitem.icon is defined and subitem.icon.class is defined %}
|
{{ render_icon_and_name(children) }}
|
||||||
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
|
|
||||||
{% else %}
|
|
||||||
<p>Missing icon in subitem: {{ subitem }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -42,12 +42,12 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarNav{{menu_type}}">
|
<div class="collapse navbar-collapse" id="navbarNav{{menu_type}}">
|
||||||
<ul class="navbar-nav {% if menu_type == 'header' %}ms-auto{% endif %}">
|
<ul class="navbar-nav {% if menu_type == 'header' %}ms-auto{% endif %}">
|
||||||
{% for item in navigation[menu_type] %}
|
{% for item in navigation[menu_type].children %}
|
||||||
{% if item.url %}
|
{% if item.url %}
|
||||||
<!-- Single Item -->
|
<!-- Single Item -->
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{{ item.url }}" target="{{ item.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ item.description }}">
|
<a class="nav-link" href="{{ item.url }}" target="{{ item.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ item.description }}">
|
||||||
<i class="{{ item.icon.class }}"></i> {{ item.name }}
|
{{ render_icon_and_name(item) }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -55,13 +55,13 @@
|
|||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" data-bs-display="dynamic" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" data-bs-display="dynamic" aria-expanded="false">
|
||||||
{% if item.icon is defined and item.icon.class is defined %}
|
{% if item.icon is defined and item.icon.class is defined %}
|
||||||
<i class="{{ item.icon.class }}"></i> {{ item.name }}
|
{{ render_icon_and_name(item) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Missing icon in item: {{ item }}</p>
|
<p>Missing icon in item: {{ item }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{{ render_subitems(item.subitems) }}
|
{{ render_children(item.children) }}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -2,7 +2,7 @@ from pprint import pprint
|
|||||||
class ConfigurationResolver:
|
class ConfigurationResolver:
|
||||||
"""
|
"""
|
||||||
A class to resolve `link` entries in a nested configuration structure.
|
A class to resolve `link` entries in a nested configuration structure.
|
||||||
Supports navigation through dictionaries, lists, and `subitems`.
|
Supports navigation through dictionaries, lists, and `children`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
@ -14,23 +14,58 @@ class ConfigurationResolver:
|
|||||||
"""
|
"""
|
||||||
self._recursive_resolve(self.config, self.config)
|
self._recursive_resolve(self.config, self.config)
|
||||||
|
|
||||||
|
def __load_children(self,path):
|
||||||
|
"""
|
||||||
|
Check if explicitly children should be loaded and not parent
|
||||||
|
"""
|
||||||
|
return path.split('.').pop() == "children"
|
||||||
|
|
||||||
|
def _replace_in_dict_by_dict(self, dict_origine, old_key, new_dict):
|
||||||
|
if old_key in dict_origine:
|
||||||
|
# Entferne den alten Key
|
||||||
|
old_value = dict_origine.pop(old_key)
|
||||||
|
# Füge die neuen Key-Value-Paare hinzu
|
||||||
|
dict_origine.update(new_dict)
|
||||||
|
|
||||||
|
def _replace_in_list_by_list(self, list_origine, old_element, new_elements):
|
||||||
|
index = list_origine.index(old_element)
|
||||||
|
list_origine[index:index+1] = new_elements
|
||||||
|
|
||||||
|
def _replace_element_in_list(self, list_origine, old_element, new_element):
|
||||||
|
index = list_origine.index(old_element)
|
||||||
|
list_origine[index] = new_element
|
||||||
|
|
||||||
def _recursive_resolve(self, current_config, root_config):
|
def _recursive_resolve(self, current_config, root_config):
|
||||||
"""
|
"""
|
||||||
Recursively resolves `link` entries in the configuration.
|
Recursively resolves `link` entries in the configuration.
|
||||||
"""
|
"""
|
||||||
if isinstance(current_config, dict):
|
if isinstance(current_config, dict):
|
||||||
for key, value in list(current_config.items()):
|
for key, value in list(current_config.items()):
|
||||||
if key == "link":
|
if key == "children":
|
||||||
|
for item in value:
|
||||||
|
if "link" in item:
|
||||||
|
loaded_link = self._find_entry(root_config, item['link'].lower(), False)
|
||||||
|
if isinstance(loaded_link, list):
|
||||||
|
self._replace_in_list_by_list(value,item,loaded_link)
|
||||||
|
else:
|
||||||
|
self._replace_element_in_list(value,item,loaded_link)
|
||||||
|
elif key == "link":
|
||||||
try:
|
try:
|
||||||
target = self._find_entry(root_config, value.lower(), True)
|
if self.__load_children(value):
|
||||||
if isinstance(target, list) and len(target) > 2:
|
loaded = self._find_entry(root_config, value.lower(), False)
|
||||||
target = self._find_entry(root_config, value.lower(), False)
|
self._replace_in_dict_by_dict(
|
||||||
current_config.clear()
|
current_config,key,loaded
|
||||||
current_config.update(target)
|
)
|
||||||
|
else:
|
||||||
|
loaded = self._find_entry(root_config, value.lower(), True)
|
||||||
|
if isinstance(loaded, list) and len(loaded) > 2:
|
||||||
|
loaded = self._find_entry(root_config, value.lower(), False)
|
||||||
|
current_config.clear()
|
||||||
|
current_config.update(loaded)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Error resolving link '{value}': {str(e)}. "
|
f"Error resolving link '{value}': {str(e)}. "
|
||||||
f"Current path: {key}, Current config: {current_config}"
|
f"Current path: {key}, Current config: {current_config}" + (f", Loaded: {loaded}" if 'loaded' in locals() or 'loaded' in globals() else "")
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._recursive_resolve(value, root_config)
|
self._recursive_resolve(value, root_config)
|
||||||
@ -38,9 +73,9 @@ class ConfigurationResolver:
|
|||||||
for item in current_config:
|
for item in current_config:
|
||||||
self._recursive_resolve(item, root_config)
|
self._recursive_resolve(item, root_config)
|
||||||
|
|
||||||
def _get_subitems(self,current):
|
def _get_children(self,current):
|
||||||
if isinstance(current, dict) and ("subitems" in current and current["subitems"]):
|
if isinstance(current, dict) and ("children" in current and current["children"]):
|
||||||
current = current["subitems"]
|
current = current["children"]
|
||||||
return current
|
return current
|
||||||
|
|
||||||
def _find_by_name(self,current, part):
|
def _find_by_name(self,current, part):
|
||||||
@ -49,33 +84,35 @@ class ConfigurationResolver:
|
|||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
def _find_entry(self, config, path, subitems):
|
def _find_entry(self, config, path, children):
|
||||||
"""
|
"""
|
||||||
Finds an entry in the configuration by a dot-separated path.
|
Finds an entry in the configuration by a dot-separated path.
|
||||||
Supports both dictionaries and lists with `subitems` navigation.
|
Supports both dictionaries and lists with `children` navigation.
|
||||||
"""
|
"""
|
||||||
parts = path.split('.')
|
parts = path.split('.')
|
||||||
current = config
|
current = config
|
||||||
for part in parts:
|
for part in parts:
|
||||||
if isinstance(current, list):
|
if isinstance(current, list):
|
||||||
# Look for a matching name in the list
|
# If children explicit declared just load children
|
||||||
found = self._find_by_name(current,part)
|
if part != "children":
|
||||||
if found:
|
# Look for a matching name in the list
|
||||||
print(
|
found = self._find_by_name(current,part)
|
||||||
f"Matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
if found:
|
||||||
f"Current list: {current}"
|
current = found
|
||||||
)
|
print(
|
||||||
else:
|
f"Matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
||||||
raise ValueError(
|
f"Current list: {current}"
|
||||||
f"No matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
)
|
||||||
f"Current list: {current}"
|
else:
|
||||||
)
|
raise ValueError(
|
||||||
current = found
|
f"No matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
||||||
|
f"Current list: {current}"
|
||||||
|
)
|
||||||
elif isinstance(current, dict):
|
elif isinstance(current, dict):
|
||||||
# Case-insensitive dictionary lookup
|
# Case-insensitive dictionary lookup
|
||||||
key = next((k for k in current if k.lower() == part), None)
|
key = next((k for k in current if k.lower() == part), None)
|
||||||
if key is None:
|
if key is None:
|
||||||
current = self._find_by_name(current["subitems"],part)
|
current = self._find_by_name(current["children"],part)
|
||||||
if not current:
|
if not current:
|
||||||
raise KeyError(
|
raise KeyError(
|
||||||
f"Key '{part}' not found in dictionary. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
f"Key '{part}' not found in dictionary. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
|
||||||
@ -89,8 +126,8 @@ class ConfigurationResolver:
|
|||||||
f"Invalid path segment '{part}'. Current type: {type(current)}. "
|
f"Invalid path segment '{part}'. Current type: {type(current)}. "
|
||||||
f"Path so far: {' > '.join(parts[:parts.index(part)+1])}"
|
f"Path so far: {' > '.join(parts[:parts.index(part)+1])}"
|
||||||
)
|
)
|
||||||
if subitems:
|
if children:
|
||||||
current = self._get_subitems(current)
|
current = self._get_children(current)
|
||||||
|
|
||||||
return current
|
return current
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user