{
[params],
);
- const isMobile = useMedia('(max-width: 600px)');
-
const size = useWindowSize();
const { hovered, markers, onClick, onMouseMove, onMouseLeave, onZoom } =
@@ -97,7 +97,7 @@ const MapComponent = ({ buildings, mapCut }: MapComponentProps) => {
generateId={true}
cluster={true}
clusterMaxZoom={17.0}
- clusterRadius={50}
+ clusterRadius={30}
clusterProperties={{
itemids: ['concat', ['concat', ['get', 'id'], ',']],
}}
diff --git a/src/app/[locale]/locations/components/map/useMapFunctions.ts b/src/app/[locale]/locations/components/map/useMapFunctions.ts
index 9584143..05b7954 100644
--- a/src/app/[locale]/locations/components/map/useMapFunctions.ts
+++ b/src/app/[locale]/locations/components/map/useMapFunctions.ts
@@ -171,7 +171,7 @@ const useMapFunctions = (
setHovered(null);
}
},
- [mapRef],
+ [mapRef?.current],
);
const onZoom = (e) => {
diff --git a/src/app/[locale]/timeline/components/container.tsx b/src/app/[locale]/timeline/components/container.tsx
index e9ed8f9..33fea7e 100644
--- a/src/app/[locale]/timeline/components/container.tsx
+++ b/src/app/[locale]/timeline/components/container.tsx
@@ -1,19 +1,18 @@
'use client';
-import { Suspense } from 'react';
+import { ReactNode, Suspense } from 'react';
import cx from 'classnames';
-import { Context, GraphQlItem } from '@/types/graphql';
-import EventBar from './eventBar.server';
+import { Context } from '@/types/graphql';
import { useCallback, useState } from 'react';
type EventContainerProps = {
- events: GraphQlItem[];
location: Context;
+ children: ReactNode;
};
export default function EventContainer({
location,
- events,
+ children,
}: EventContainerProps) {
const [isOpen, setIsOpen] = useState(false);
@@ -24,27 +23,12 @@ export default function EventContainer({
return (
-
+
{location.name}
-
- {isOpen && (
-
-
- {events.map((event) => (
-
- ))}
-
-
- )}
-
+ {isOpen &&
{children}}
{event.name}
;
+ return (
+
{event.name}
+ );
}
diff --git a/src/app/[locale]/timeline/components/eventLocation.server.tsx b/src/app/[locale]/timeline/components/eventLocation.server.tsx
index 48bb802..fe93d95 100644
--- a/src/app/[locale]/timeline/components/eventLocation.server.tsx
+++ b/src/app/[locale]/timeline/components/eventLocation.server.tsx
@@ -1,14 +1,30 @@
import { Context } from '@/types/graphql';
import { getEventList } from '@/api/rest/events';
import EventContainer from './container';
+import EventBar from './eventBar.server';
+import { TIMES } from '@/api/constants';
+
+import TimeScale from './scale';
+
type EventLocationProps = {
location: Context;
};
-export const revalidate = 5000;
+export const revalidate = 0;
export default async function EventLocation({ location }: EventLocationProps) {
const events = await getEventList(location.id);
if (events?.length == 0) return;
- return
;
+ return (
+
+ <>
+
+
+ {events.map((event) => (
+
+ ))}
+
+ >
+
+ );
}
diff --git a/src/app/[locale]/timeline/components/scale.tsx b/src/app/[locale]/timeline/components/scale.tsx
new file mode 100644
index 0000000..c8eb8dc
--- /dev/null
+++ b/src/app/[locale]/timeline/components/scale.tsx
@@ -0,0 +1,19 @@
+import cx from 'classnames';
+
+export default function TimeScale({ ticks }) {
+ return (
+
+ {ticks.map(([pos, str]) => (
+
+ {str}
+
+ ))}
+
+ );
+}
diff --git a/src/app/[locale]/timeline/components/timetable.server.tsx b/src/app/[locale]/timeline/components/timetable.server.tsx
index cb44d3e..30ea8d7 100644
--- a/src/app/[locale]/timeline/components/timetable.server.tsx
+++ b/src/app/[locale]/timeline/components/timetable.server.tsx
@@ -6,7 +6,7 @@ export default async function TimeTable() {
const items = await getEventLocations();
return (
-
+
{items.map((eventLocation) => (
))}
diff --git a/src/app/[locale]/timeline/page.tsx b/src/app/[locale]/timeline/page.tsx
index 758aaee..84852f6 100644
--- a/src/app/[locale]/timeline/page.tsx
+++ b/src/app/[locale]/timeline/page.tsx
@@ -2,7 +2,7 @@ import TimeTable from './components/timetable.server';
export default async function TimelinesPage(props: any) {
return (
-
+
);
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
index 8bb2444..ad4dec7 100644
--- a/src/app/sitemap.ts
+++ b/src/app/sitemap.ts
@@ -13,12 +13,14 @@ export default function sitemap(): MetadataRoute.Sitemap {
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
- return keys.map((key) => ({
- url: getUrl(key, defaultLocale),
- alternates: {
- languages: Object.fromEntries(
- locales.map((locale) => [locale, getUrl(key, locale)]),
- ),
- },
- }));
+ return keys
+ .filter((k) => !k.includes('['))
+ .map((key) => ({
+ url: getUrl(key, defaultLocale),
+ alternates: {
+ languages: Object.fromEntries(
+ locales.map((locale) => [locale, getUrl(key, locale)]),
+ ),
+ },
+ }));
}
diff --git a/src/components/modal/content.server.tsx b/src/components/modal/content.server.tsx
new file mode 100644
index 0000000..4bdf311
--- /dev/null
+++ b/src/components/modal/content.server.tsx
@@ -0,0 +1,17 @@
+import { ResponsiveMultiLineText } from '@/components/texts/multiLine';
+import { getTranslations } from 'next-intl/server';
+
+export default async function Content(props: { title: 'Contact' | 'Imprint' }) {
+ const t = await getTranslations(props.title);
+ return (
+
+ );
+}
diff --git a/src/components/modal/modal.tsx b/src/components/modal/modal.tsx
new file mode 100644
index 0000000..70fbcdc
--- /dev/null
+++ b/src/components/modal/modal.tsx
@@ -0,0 +1,44 @@
+'use client';
+
+import { type ElementRef, useEffect, useRef, useCallback } from 'react';
+import { usePathname, useRouter } from '@/navigation';
+import cx from 'classnames';
+import { createPortal } from 'react-dom';
+import SmoothButton from '../smoothbutton';
+
+export default function Modal({ children }: { children: React.ReactNode }) {
+ const router = useRouter();
+ const dialogRef = useRef>(null);
+ const path = usePathname();
+ const margin = path == '/imprint' ? '' : 'm-0';
+
+ useEffect(() => {
+ if (!dialogRef.current?.open) {
+ dialogRef.current?.show();
+ }
+ }, []);
+
+ const onDismiss = useCallback(() => {
+ router.back();
+ }, [router]);
+
+ return createPortal(
+ ,
+ document.getElementById('modal-root')!,
+ );
+}
diff --git a/src/components/navigationLink.tsx b/src/components/navigationLink.tsx
index ac4515b..af10b75 100644
--- a/src/components/navigationLink.tsx
+++ b/src/components/navigationLink.tsx
@@ -2,7 +2,7 @@
import cx from 'classnames';
import { useSelectedLayoutSegment } from 'next/navigation';
-import { Link } from '@/navigation';
+import { Link, usePathname } from '@/navigation';
export type NavigationLinkProps = {
href: any;
@@ -16,14 +16,15 @@ export type NavigationLinkProps = {
export default function NavigationLink({
href,
isFooter = false,
- isFirst = false,
- isLast = false,
+ isFirst = false,
+ isLast = false,
children,
}: NavigationLinkProps) {
const selectedLayoutSegment = useSelectedLayoutSegment();
- const pathname = selectedLayoutSegment ? `/${selectedLayoutSegment}` : '/';
+ const pathname = usePathname();
+ const selPathname = selectedLayoutSegment ? `/${selectedLayoutSegment}` : '/';
- const isActive = pathname === href;
+ const isActive = pathname === href || selPathname == href;
const activeStyle = isFooter
? href === '/design'
? 'rounded-border'
@@ -37,14 +38,16 @@ export default function NavigationLink({
'm-[1px] border-0 bg-secondary hover:bg-highlight hover:text-primary',
isFooter ? 'my-border' : 'my-border',
isActive ? activeStyle : 'rounded-border',
- isFirst && 'ml-border',
- isLast && 'mr-border'
+ isFirst && 'ml-border',
+ isLast && 'mr-border',
)}
+ replace={
+ (pathname == '/imprint' && href == '/contact') ||
+ (pathname == '/contact' && href == '/imprint')
+ }
href={href}
>
-
- {children}
-
+ {children}
);
}
diff --git a/src/components/texts/multiLine.tsx b/src/components/texts/multiLine.tsx
index c6ec7e5..58d74a3 100644
--- a/src/components/texts/multiLine.tsx
+++ b/src/components/texts/multiLine.tsx
@@ -15,7 +15,7 @@ export function ResponsiveMultiLineText({
className={className}
textSize={textSize}
dangerouslySetInnerHTML={{
- __html: text.replace(/[\r\n]/g, '
'),
+ __html: text,
}}
/>
);
diff --git a/src/config.ts b/src/config.ts
index e066e4f..dfef2e6 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -42,6 +42,10 @@ export const pathnames = {
en: '/project',
de: '/project',
},
+ '/project/[id]': {
+ en: '/project/[id]',
+ de: '/project/[id]',
+ },
'/timeline': {
en: '/timeline',
de: '/zeitplan',
diff --git a/src/styles/app.css b/src/styles/app.css
index 5a5840f..335535f 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -14,8 +14,11 @@
--height-header: 50px;
--height-content: calc(100dvh - var(--height-header) - var(--height-footer));
+ --height-modal: calc(100dvh - var(--height-footer));
--height-content-header: 0px;
- --height-content-body: calc(var(--height-content) - var(--height-content-header));
+ --height-content-body: calc(
+ var(--height-content) - var(--height-content-header)
+ );
--height-footer: 50px;
}
@@ -72,7 +75,6 @@ body {
scrollbar-width: none;
}
-
@media (prefers-color-scheme: dark) {
:root {
--primary: 255, 255, 255;
diff --git a/src/types/types.ts b/src/types/types.ts
index 1567022..55e5eeb 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -1,4 +1,4 @@
-import { Context } from '@/types/graphql';
+import { Context, GraphQlItem } from '@/types/graphql';
import { ReactNode } from 'react';
export type ResponsiveSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
@@ -9,9 +9,9 @@ export type LocalizesObject = {
};
export type InfoItem = {
- id: number;
+ id: string;
title: string;
- content: string;
+ text: string;
};
export type ReactNodeProps = {
@@ -36,8 +36,8 @@ export type Filter = Pick & {
};
export type FilterHeader = {
- id: number,
- title: 'faculties' | 'formats' | 'languages';
+ id: number;
+ title: 'faculties' | 'formats' | 'languages';
};
export type Building = {
@@ -51,3 +51,8 @@ export type Building = {
export type ContextTree = Context & {
children: { [key: string]: ContextTree };
};
+
+export type EventItem = GraphQlItem & {
+ left: string;
+ width: string;
+};
diff --git a/tailwind.config.ts b/tailwind.config.ts
index acaabba..eee5424 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -88,11 +88,26 @@ const config: Config = {
'content-header': 'var(--height-content-header)',
content: 'var(--height-content)',
'content-height': 'var(--height-content-height)',
+ modal: 'var(--height-modal)',
'content-body': 'var(--height-content-body)',
footer: 'var(--height-footer)',
'design-projects':
'calc(100dvh - var(--height-header) - var(--height-footer) - var(--height-content-header))',
},
+ minHeight: {
+ header: 'var(--height-header)',
+ 'content-header': 'var(--height-content-header)',
+ content: 'var(--height-content)',
+ 'content-height': 'var(--height-content-height)',
+ 'content-body': 'var(--height-content-body)',
+ footer: 'var(--height-footer)',
+ 'design-projects':
+ 'calc(100dvh - var(--height-header) - var(--height-footer) - var(--height-content-header))',
+ },
+ top: {
+ header: 'var(--height-header)',
+ 'content-header': 'var(--height-content-header)',
+ },
borderRadius: {
md: '4px',
border: '4px',
@@ -109,6 +124,15 @@ const config: Config = {
'gutter-md': '20px',
'gutter-lg': '50px',
border: '2px',
+ header: 'var(--height-header)',
+ 'content-header': 'var(--height-content-header)',
+ footer: 'var(--height-footer)',
+ },
+ inset: {
+ border: '2px',
+ header: 'var(--height-header)',
+ 'content-header': 'var(--height-content-header)',
+ footer: 'var(--height-footer)',
},
gridTemplateColumns: {
'header-info': 'minmax(100px, 1fr) 50px 50px 50px',