mirror of
				https://github.com/kevinveenbirkenbach/homepage.veen.world.git
				synced 2025-10-31 15:39:02 +00:00 
			
		
		
		
	Refactored code and implemented new childrens loading
This commit is contained in:
		
							
								
								
									
										505
									
								
								app/config.yaml
									
									
									
									
									
								
							
							
						
						
									
										505
									
								
								app/config.yaml
									
									
									
									
									
								
							| @@ -4,12 +4,12 @@ accounts: | ||||
|   description: My Online Accounts | ||||
|   icon: | ||||
|       class: fa-solid fa-users | ||||
|   subitems: | ||||
|   children: | ||||
|   - name: Publications | ||||
|     description: My Publications | ||||
|     icon: | ||||
|         class: fas fa-newspaper | ||||
|     subitems: | ||||
|     children: | ||||
|     - name: Microblog | ||||
|       description: Read my microblogs | ||||
|       icon: | ||||
| @@ -19,7 +19,7 @@ accounts: | ||||
|     - name: Pictures | ||||
|       icon: | ||||
|         class: fa-solid fa-images | ||||
|       subitems: | ||||
|       children: | ||||
|       - name: Pixelfed   | ||||
|         description: View my photo gallery | ||||
|         icon: | ||||
| @@ -49,7 +49,7 @@ accounts: | ||||
|       icon: | ||||
|           class: fa-solid fa-laptop-code | ||||
|       description: Check out my Code | ||||
|       subitems: | ||||
|       children: | ||||
|       - name: Github | ||||
|         description: View my GitHub profile | ||||
|         icon: | ||||
| @@ -66,7 +66,7 @@ accounts: | ||||
|     icon: | ||||
|       class: fa-brands fa-meta | ||||
|     url:  | ||||
|     subitems: | ||||
|     children: | ||||
|     - name: Facebook | ||||
|       description: Like my Facebook page | ||||
|       icon: | ||||
| @@ -76,7 +76,7 @@ accounts: | ||||
|   - name: Carreer Profiles | ||||
|     icon: | ||||
|       class: fa-solid fa-user-tie | ||||
|     subitems: | ||||
|     children: | ||||
|     - name: XING | ||||
|       description: Visit my XING profile | ||||
|       icon: | ||||
| @@ -94,7 +94,7 @@ accounts: | ||||
|     icon: | ||||
|       class: fa-solid fa-running | ||||
|     url:  | ||||
|     subitems: | ||||
|     children: | ||||
|     - name: Garmin | ||||
|       description: My Garmin activities | ||||
|       icon: | ||||
| @@ -250,263 +250,266 @@ company: | ||||
|     country: Germany | ||||
|   imprint_url: https://s.veen.world/imprint | ||||
| navigation: | ||||
|   header:       | ||||
|   - name: Contact | ||||
|     description: Get in touch | ||||
|     icon: | ||||
|         class: fa-solid fa-envelope | ||||
|     subitems: | ||||
|     - name: Email | ||||
|       description: Send me an email | ||||
|   header: | ||||
|     children: | ||||
|     - link: accounts.publications.children | ||||
|     - name: Contact | ||||
|       description: Get in touch | ||||
|       icon: | ||||
|         class: fa-solid fa-envelope | ||||
|       subitems: | ||||
|           class: fa-solid fa-envelope | ||||
|       children: | ||||
|       - name: Email | ||||
|         description: Send me an email | ||||
|         icon: | ||||
|           class: fa-solid fa-envelope | ||||
|         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 | ||||
|         children: | ||||
|         - name: Email | ||||
|           description: Send me an email | ||||
|           icon: | ||||
|             class: fa-solid fa-envelope | ||||
|           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: | ||||
|           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: | ||||
|         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 | ||||
|           class: fa-solid fa-phone | ||||
|         url: "tel:+491781798023" | ||||
|         identifier: "+491781798023" | ||||
|         warning: Signal is not hosted by me! | ||||
|         alternatives: | ||||
|           - link: navigation.header.contact.messenger.matrix | ||||
|       - name: Telegram | ||||
|         description: Message me on Telegram | ||||
|         target: _top | ||||
|       - name: Messenger | ||||
|         description: Social and developer networks | ||||
|         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 | ||||
|           class: fa-solid fa-comments | ||||
|         children:  | ||||
|         - 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" | ||||
|           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: | ||||
|   - link: accounts | ||||
|   - name: Solution Hub | ||||
|     description: Curated collection of self hosted tools | ||||
|     icon: | ||||
|         class: fa-solid fa-network-wired | ||||
|     url:  | ||||
|     subitems: | ||||
|     - name: Community | ||||
|       description: Tools to manage the community | ||||
|     children: | ||||
|     - link: accounts | ||||
|     - name: Solution Hub | ||||
|       description: Curated collection of self hosted tools | ||||
|       icon: | ||||
|           class: fa-solid fa-users | ||||
|       subitems: | ||||
|       - name: Forum | ||||
|         description: Join the discussion | ||||
|           class: fa-solid fa-network-wired | ||||
|       url:  | ||||
|       children: | ||||
|       - name: Community | ||||
|         description: Tools to manage the community | ||||
|         icon: | ||||
|           class: fa-brands fa-discourse | ||||
|         url: https://forum.veen.world/ | ||||
|       - name: Learning Platform | ||||
|         description: Learn with my academy | ||||
|         icon: | ||||
|           class: fa-solid fa-graduation-cap | ||||
|         url: https://academy.veen.world/ | ||||
|       - name: Newsletter | ||||
|         description: Subscribe to my newsletter | ||||
|         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 | ||||
|             class: fa-solid fa-users | ||||
|         children: | ||||
|         - name: Forum | ||||
|           description: Join the discussion | ||||
|           icon: | ||||
|             class: fa-brands fa-discourse | ||||
|           url: https://forum.veen.world/ | ||||
|         - name: Learning Platform | ||||
|           description: Learn with my academy | ||||
|           icon: | ||||
|             class: fa-solid fa-graduation-cap | ||||
|           url: https://s.veen.world/degrees | ||||
|         - name: Certificates | ||||
|           description: View my training and professional development records | ||||
|           url: https://academy.veen.world/ | ||||
|         - name: Newsletter | ||||
|           description: Subscribe to my newsletter | ||||
|           icon: | ||||
|             class: fa-solid fa-certificate | ||||
|           url: https://s.veen.world/certificates | ||||
|         - name: Certifications | ||||
|           description: Browse all my certifications | ||||
|             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 | ||||
|         children: | ||||
|         - name: Open Project | ||||
|           description: Explore my projects | ||||
|           icon: | ||||
|             class: fa-solid fa-scroll | ||||
|           url: https://s.veen.world/certifications | ||||
|     - link: accounts | ||||
|        | ||||
|   - name: Imprint | ||||
|     description: Check out the imprint information | ||||
|     icon: | ||||
|         class: fa-solid fa-scale-balanced | ||||
|     url: https://s.veen.world/imprint | ||||
|             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 | ||||
|         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_subitems(subitems) %} | ||||
|     {% for subitem in subitems %} | ||||
|         {% if subitem.subitems %} | ||||
| {% macro render_icon_and_name(item) %} | ||||
|     <i class="{{ item.icon.class if item.icon is defined and item.icon.class is defined else 'fa-solid fa-link' }}"></i> | ||||
|     {% if item.name is defined %} | ||||
|         {{ 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"> | ||||
|                 <a class="dropdown-item dropdown-toggle" href="#" title="{{ subitem.description }}"> | ||||
|                     {% if subitem.icon is defined and subitem.icon.class is defined %} | ||||
|                         <i class="{{ subitem.icon.class }}"></i> {{ subitem.name }} | ||||
|                     {% else %} | ||||
|                         <p>Missing icon in subitem: {{ subitem }}</p> | ||||
|                     {% endif %} | ||||
|                 <a class="dropdown-item dropdown-toggle" href="#" title="{{ children.description }}"> | ||||
|                     {{ render_icon_and_name(children) }} | ||||
|                 </a> | ||||
|                 <ul class="dropdown-menu"> | ||||
|                     {{ render_subitems(subitem.subitems) }} | ||||
|                     {{ render_children(children.children) }} | ||||
|                 </ul> | ||||
|             </li> | ||||
|         {% elif subitem.identifier or subitem.warning or subitem.info %} | ||||
|         {% elif children.identifier or children.warning or children.info %} | ||||
|             <li> | ||||
|                 <a class="dropdown-item" onclick='openDynamicPopup({{ subitem|tojson|safe }})' data-bs-toggle="tooltip" title="{{ subitem.description }}"> | ||||
|                     <i class="{{ subitem.icon.class }}"></i> {{ subitem.name }} | ||||
|                 <a class="dropdown-item" onclick='openDynamicPopup({{ children|tojson|safe }})' data-bs-toggle="tooltip" title="{{ children.description }}"> | ||||
|                     {{ render_icon_and_name(children) }} | ||||
|                 </a> | ||||
|             </li> | ||||
|         {% else %} | ||||
|             <li> | ||||
|                 <a class="dropdown-item" href="{{ subitem.url }}" target="{{ subitem.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ subitem.description }}"> | ||||
|                     {% if subitem.icon is defined and subitem.icon.class is defined %} | ||||
|                         <i class="{{ subitem.icon.class }}"></i> {{ subitem.name }} | ||||
|                     {% else %} | ||||
|                         <p>Missing icon in subitem: {{ subitem }}</p> | ||||
|                     {% endif %} | ||||
|                 <a class="dropdown-item" href="{{ children.url }}" target="{{ children.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ children.description }}"> | ||||
|                      {{ render_icon_and_name(children) }} | ||||
|                 </a> | ||||
|             </li> | ||||
|         {% endif %} | ||||
| @@ -42,12 +42,12 @@ | ||||
|         </button> | ||||
|         <div class="collapse navbar-collapse" id="navbarNav{{menu_type}}"> | ||||
|             <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 %} | ||||
|                         <!-- Single Item --> | ||||
|                         <li class="nav-item"> | ||||
|                             <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> | ||||
|                         </li> | ||||
|                     {% else %} | ||||
| @@ -55,13 +55,13 @@ | ||||
|                         <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"> | ||||
|                                 {% 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 %} | ||||
|                                     <p>Missing icon in item: {{ item }}</p> | ||||
|                                 {% endif %} | ||||
|                             </a> | ||||
|                             <ul class="dropdown-menu"> | ||||
|                                 {{ render_subitems(item.subitems) }} | ||||
|                                 {{ render_children(item.children) }} | ||||
|                             </ul> | ||||
|                         </li> | ||||
|                     {% endif %} | ||||
|   | ||||
| @@ -2,7 +2,7 @@ from pprint import pprint | ||||
| class ConfigurationResolver: | ||||
|     """ | ||||
|     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): | ||||
| @@ -14,23 +14,58 @@ class ConfigurationResolver: | ||||
|         """ | ||||
|         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): | ||||
|         """ | ||||
|         Recursively resolves `link` entries in the configuration. | ||||
|         """ | ||||
|         if isinstance(current_config, dict): | ||||
|             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: | ||||
|                         target = self._find_entry(root_config, value.lower(), True) | ||||
|                         if isinstance(target, list) and len(target) > 2: | ||||
|                             target = self._find_entry(root_config, value.lower(), False)     | ||||
|                         current_config.clear() | ||||
|                         current_config.update(target) | ||||
|                         if self.__load_children(value): | ||||
|                             loaded = self._find_entry(root_config, value.lower(), False) | ||||
|                             self._replace_in_dict_by_dict( | ||||
|                                     current_config,key,loaded | ||||
|                                 ) | ||||
|                         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:  | ||||
|                         raise ValueError( | ||||
|                             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: | ||||
|                     self._recursive_resolve(value, root_config) | ||||
| @@ -38,9 +73,9 @@ class ConfigurationResolver: | ||||
|             for item in current_config: | ||||
|                 self._recursive_resolve(item, root_config) | ||||
|  | ||||
|     def _get_subitems(self,current): | ||||
|         if isinstance(current, dict) and ("subitems" in current and current["subitems"]): | ||||
|             current = current["subitems"] | ||||
|     def _get_children(self,current): | ||||
|         if isinstance(current, dict) and ("children" in current and current["children"]): | ||||
|             current = current["children"] | ||||
|         return current | ||||
|  | ||||
|     def _find_by_name(self,current, part): | ||||
| @@ -49,33 +84,35 @@ class ConfigurationResolver: | ||||
|                     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. | ||||
|         Supports both dictionaries and lists with `subitems` navigation. | ||||
|         Supports both dictionaries and lists with `children` navigation. | ||||
|         """ | ||||
|         parts = path.split('.') | ||||
|         current = config | ||||
|         for part in parts: | ||||
|             if isinstance(current, list): | ||||
|                 # Look for a matching name in the list | ||||
|                 found = self._find_by_name(current,part) | ||||
|                 if found: | ||||
|                     print( | ||||
|                         f"Matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. " | ||||
|                         f"Current list: {current}" | ||||
|                     ) | ||||
|                 else: | ||||
|                     raise ValueError( | ||||
|                         f"No matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. " | ||||
|                         f"Current list: {current}" | ||||
|                     ) | ||||
|                 current = found | ||||
|                 # If children explicit declared just load children | ||||
|                 if part != "children": | ||||
|                     # Look for a matching name in the list | ||||
|                     found = self._find_by_name(current,part) | ||||
|                     if found: | ||||
|                         current = found | ||||
|                         print( | ||||
|                             f"Matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. " | ||||
|                             f"Current list: {current}" | ||||
|                         ) | ||||
|                     else: | ||||
|                         raise ValueError( | ||||
|                             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): | ||||
|                 # Case-insensitive dictionary lookup | ||||
|                 key = next((k for k in current if k.lower() == part), None) | ||||
|                 if key is None: | ||||
|                     current = self._find_by_name(current["subitems"],part) | ||||
|                     current = self._find_by_name(current["children"],part) | ||||
|                     if not current: | ||||
|                         raise KeyError( | ||||
|                             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"Path so far: {' > '.join(parts[:parts.index(part)+1])}" | ||||
|                 ) | ||||
|             if subitems: | ||||
|                 current = self._get_subitems(current) | ||||
|             if children: | ||||
|                 current = self._get_children(current) | ||||
|  | ||||
|         return current | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user