From e326b7e2540f3a3b9973c88f336081a081f33c25 Mon Sep 17 00:00:00 2001 From: Liliana Sanfilippo <liliana.sanfilippo@uni-bielefeld.de> Date: Mon, 23 Sep 2024 01:02:26 +0200 Subject: [PATCH] openElement --- src/App/App.tsx | 5 +- src/utils/TabNavigation.tsx | 49 +++++++++++------ src/utils/openElement.ts | 102 +++++++++++++++++++----------------- src/utils/useNavigation.ts | 52 ++++++++---------- 4 files changed, 111 insertions(+), 97 deletions(-) diff --git a/src/App/App.tsx b/src/App/App.tsx index e8bff3de..098917d3 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -22,15 +22,18 @@ import { Villbuttonrow } from "../components/Buttons.tsx"; import "../utils/Highlight-functions.js"; import "./LoadingScreen.css"; import { useScroll, motion } from "framer-motion"; +import { useNavigation } from "../utils/useNavigation.ts"; const App = () => { + const { isLoading, setIsLoading, goToPagesAndOpenTab, goToPageWithTabAndScroll } = useNavigation(); + const { scrollYProgress } = useScroll({ offset: ["start start", "end end"], }); window.scrollTo(0, 0); - const [isLoading, setIsLoading] = useState(true); + const pathMapping = getPathMapping(); const currentPath = diff --git a/src/utils/TabNavigation.tsx b/src/utils/TabNavigation.tsx index 9ddbb7bf..23bb5504 100644 --- a/src/utils/TabNavigation.tsx +++ b/src/utils/TabNavigation.tsx @@ -1,26 +1,24 @@ -import { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; import { openFromOtherPage } from './openFromOtherpAge'; +// Funktion, um den Haupttab zu öffnen export const openTab = (tabId: string) => { - // Hide all tabs const tabs = document.querySelectorAll('.tabcontent'); tabs.forEach((tab) => { (tab as HTMLElement).style.display = 'none'; }); - // Show the selected tab const selectedTab = document.getElementById(tabId); if (selectedTab) { selectedTab.style.display = 'block'; } }; +// Funktion, um verschachtelte Tabs zu öffnen export const openNestedTab = (parentTabId: string, childTabId: string) => { - // Open parent tab openTab(parentTabId); - // Open child tab inside parent tab const nestedTabs = document.querySelectorAll(`#${parentTabId} .nested-tabcontent`); nestedTabs.forEach((tab) => { (tab as HTMLElement).style.display = 'none'; @@ -32,6 +30,7 @@ export const openNestedTab = (parentTabId: string, childTabId: string) => { } }; +// Funktion, um zu einem bestimmten Bereich (z.B. Collapse) zu scrollen export const handleScrollToCollapse = (collapseId: string) => { const collapseElement = document.getElementById(collapseId); if (collapseElement) { @@ -46,38 +45,56 @@ export const handleScrollToCollapse = (collapseId: string) => { } }; -export const TabNavigation = () => { +// Custom Hook zur zentralen Tab-Navigation +export const useTabNavigation = () => { + const navigate = useNavigate(); const location = useLocation(); + const [activeTab, setActiveTab] = useState<string | null>(null); + const [activeSubTab, setActiveSubTab] = useState<string | null>(null); + + // Tab-Wechsel und URL-Update + const handleTabChange = (tabId: string, subTabId?: string) => { + setActiveTab(tabId); + setActiveSubTab(subTabId || null); + + // URL entsprechend aktualisieren + let newUrl = `${location.pathname}?tab=${tabId}`; + if (subTabId) { + newUrl += `&subTab=${subTabId}`; + } + navigate(newUrl, { replace: true }); + }; useEffect(() => { const params = new URLSearchParams(location.search); - const collapseId = params.get('collapseId'); const tabId = params.get('tab'); - const subTabId = params.get('subTab'); // Neues Parameter für verschachtelte Tabs + const subTabId = params.get('subTab'); + const collapseId = params.get('collapseId'); - // Open the tab specified by tabId (and subTab if nested) + // Öffne Haupt- und ggf. verschachtelten Tab if (tabId) { if (subTabId) { - // If subTab is provided, open the nested tab openNestedTab(tabId, subTabId); } else { - // Otherwise, just open the main tab openTab(tabId); } } - // Scroll to the section specified by collapseId after opening the tab + // Scrollen zu einem bestimmten Collapsible-Element if (collapseId) { handleScrollToCollapse(collapseId); } - // Open the tab from another page + // Tab von einer anderen Seite öffnen (falls definiert) if (tabId) { openFromOtherPage(tabId)({ currentTarget: document.getElementById(tabId)! }); } + + setActiveTab(tabId); + setActiveSubTab(subTabId || null); }, [location.search]); - return + return { activeTab, activeSubTab, handleTabChange }; }; -export default TabNavigation; + diff --git a/src/utils/openElement.ts b/src/utils/openElement.ts index a4fbaeaa..19ac2f1a 100644 --- a/src/utils/openElement.ts +++ b/src/utils/openElement.ts @@ -1,52 +1,56 @@ export function openElement({ - elementToOpen, - classToHide, /* tabcontent */ - elementToClose, - buttonClass, /* = "tablinks" */ - eventTargetClass = "active" - }: { - elementToOpen: string, - classToHide: string, - classToClose?: string, - elementToClose?: string, - buttonClass?: string, - eventTargetClass?: string - }) { - const openElement = (event: React.MouseEvent<HTMLElement, MouseEvent>) => { - let i, elementsToHide, elementsToClose, tabLinks; - - // Hide all elements with the classToHide (e.g., "tabcontent") - elementsToHide = document.getElementsByClassName(classToHide); - for (i = 0; i < elementsToHide.length; i++) { - (elementsToHide[i] as HTMLElement).style.display = "none"; + elementToOpen, + classToHide, /* tabcontent */ + elementToClose, + buttonClass, /* = "tablinks" */ + eventTargetClass = "active", + handleTabChange /* Hier handleTabChange als Parameter einfügen */ +}: { + elementToOpen: string, + classToHide: string, + classToClose?: string, + elementToClose?: string, + buttonClass?: string, + eventTargetClass?: string, + handleTabChange: (tabId: string, subTabId?: string) => void /* Neuer Parameter für die Tab-Änderungslogik */ +}) { + const openElement = (event: React.MouseEvent<HTMLElement, MouseEvent>) => { + let i, elementsToHide, elementsToClose, tabLinks; + + // Hide all elements with the classToHide (e.g., "tabcontent") + elementsToHide = document.getElementsByClassName(classToHide); + for (i = 0; i < elementsToHide.length; i++) { + (elementsToHide[i] as HTMLElement).style.display = "none"; + } + + // If elementToClose is provided, hide these elements too (optional) + if (elementToClose) { + elementsToClose = document.getElementsByClassName(elementToClose); + for (i = 0; i < elementsToClose.length; i++) { + (elementsToClose[i] as HTMLElement).style.display = "none"; } - - // If elementToClose is provided, hide these elements too (optional) - if (elementToClose) { - elementsToClose = document.getElementsByClassName(elementToClose); - for (i = 0; i < elementsToClose.length; i++) { - (elementsToClose[i] as HTMLElement).style.display = "none"; - } + } + + // Clear the "active" class from elements with the buttonClass (e.g., "tablinks") + if (buttonClass) { + tabLinks = document.getElementsByClassName(buttonClass); + for (i = 0; i < tabLinks.length; i++) { + tabLinks[i].className = tabLinks[i].className.replace(` ${eventTargetClass}`, ""); } - - // Clear the "active" class from elements with the buttonClass (e.g., "tablinks") - if (buttonClass) { - tabLinks = document.getElementsByClassName(buttonClass); - for (i = 0; i < tabLinks.length; i++) { - tabLinks[i].className = tabLinks[i].className.replace(` ${eventTargetClass}`, ""); - } - } - - // Display the element to open (elementToOpen, e.g., a city tab or content section) - const element = document.getElementById(elementToOpen); - if (element) { - element.style.display = "block"; - } - - // Add the "active" class to the clicked element - event.currentTarget.className += ` ${eventTargetClass}`; - }; - - return openElement; - } - \ No newline at end of file + } + + // Display the element to open (elementToOpen, e.g., a city tab or content section) + const element = document.getElementById(elementToOpen); + if (element) { + element.style.display = "block"; + } + + // Add the "active" class to the clicked element + event.currentTarget.className += ` ${eventTargetClass}`; + + // Rufe handleTabChange auf, um die URL entsprechend anzupassen + handleTabChange(elementToOpen); // Hier wird die Tab-Änderung und URL-Update durchgeführt + }; + + return openElement; +} diff --git a/src/utils/useNavigation.ts b/src/utils/useNavigation.ts index d3796381..39f76f7d 100644 --- a/src/utils/useNavigation.ts +++ b/src/utils/useNavigation.ts @@ -1,58 +1,48 @@ -import { useNavigate } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; +import { useState, useEffect, useRef } from "react"; export const useNavigation = () => { const navigate = useNavigate(); + const location = useLocation(); + const previousPath = useRef(location.pathname); + const [isLoading, setIsLoading] = useState(false); + const goToPagesAndOpenTab = (tabId: string, path: string) => { - navigate(`${path}?tab=${tabId}`); - }; - - const goToTextsAndOpenCollapsible = (collapseId: string, path: string) => { - navigate(`${path}?collapseId=${collapseId}`); - }; - - const goToPageWithTabAndCollapsible = ({ path, tabId, collapseId }: { path: string, tabId: string, collapseId?: string }) => { - let url = `${path}?tab=${tabId}`; - if (collapseId) { - url += `&collapseId=${collapseId}`; + if (previousPath.current !== path) { + setIsLoading(true); } - navigate(url); - }; - - const goToPageWithNestedTabs = ({ path, tabId, subTabId, collapseId }: { path: string, tabId: string, subTabId?: string, collapseId?: string }) => { - let url = `${path}?tab=${tabId}`; - if (subTabId) { - url += `&subTab=${subTabId}`; - } - if (collapseId) { - url += `&collapseId=${collapseId}`; - } - navigate(url); + navigate(`${path}?tab=${tabId}`); + setTimeout(() => setIsLoading(false), 500); }; - // Erweiterte Funktion, die auch zu einer bestimmten ID innerhalb eines Tabs scrollen kann const goToPageWithTabAndScroll = ({ path, tabId, scrollToId }: { path: string, tabId: string, scrollToId?: string }) => { + if (previousPath.current !== path) { + setIsLoading(true); + } let url = `${path}?tab=${tabId}`; if (scrollToId) { url += `&scrollTo=${scrollToId}`; } navigate(url); - - // Führe nach der Navigation das Scrollen aus setTimeout(() => { + setIsLoading(false); if (scrollToId) { const element = document.getElementById(scrollToId); if (element) { - // Berechne die Scroll-Position, um das Element in der Mitte zu setzen const viewportHeight = window.innerHeight; const targetPosition = element.getBoundingClientRect().top + window.pageYOffset; const scrollToPosition = targetPosition - viewportHeight / 2 + element.clientHeight / 2; - window.scrollTo({ top: scrollToPosition, behavior: "smooth" }); } } - }, 500); // Verzögere das Scrollen, um sicherzustellen, dass der Tab geladen ist + }, 500); }; - return { goToPagesAndOpenTab, goToTextsAndOpenCollapsible, goToPageWithTabAndCollapsible, goToPageWithNestedTabs, goToPageWithTabAndScroll }; + + useEffect(() => { + previousPath.current = location.pathname; + }, [location.pathname]); + + return { isLoading, setIsLoading, goToPagesAndOpenTab, goToPageWithTabAndScroll }; }; -- GitLab