From e88f58f550456dec8967ab00efd995b4ffa3f1cc Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 08:50:45 +0200 Subject: [PATCH 01/35] feat: scroll safe layout --- app/components/error-message.tsx | 6 ++++-- app/root.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/components/error-message.tsx b/app/components/error-message.tsx index d340919b..57b7a380 100644 --- a/app/components/error-message.tsx +++ b/app/components/error-message.tsx @@ -155,7 +155,7 @@ export default function ErrorMessage() { } return ( -
+
@@ -169,7 +169,9 @@ export default function ErrorMessage() {

)} {title} - {message} + + {message} + diff --git a/app/root.tsx b/app/root.tsx index b26489f7..734ce9d8 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -264,7 +264,7 @@ export function ErrorBoundary() { -
+
From f333934bb31e8f14ac993526eba221177a0fecc9 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 08:51:15 +0200 Subject: [PATCH 02/35] feat: width on small screen --- app/components/language-select.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/language-select.tsx b/app/components/language-select.tsx index 43830d23..2060fa3e 100644 --- a/app/components/language-select.tsx +++ b/app/components/language-select.tsx @@ -41,7 +41,7 @@ export function LanguageSelect() { ) }} > - + From 20e16340b9f40f47708df8c27d0ff3701851f378 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 08:51:51 +0200 Subject: [PATCH 03/35] feat: width on small screen --- app/components/theme-select.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/theme-select.tsx b/app/components/theme-select.tsx index 8a5bd3d5..3ec96ab0 100644 --- a/app/components/theme-select.tsx +++ b/app/components/theme-select.tsx @@ -76,7 +76,7 @@ export function ThemeSelect() { ) }} > - + From e80535686918af37040e7df03181dc736dba98d9 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:24:29 +0200 Subject: [PATCH 04/35] feat: stack items --- app/routes/settings.account.tsx | 12 +++++++----- app/routes/settings.preferences.tsx | 27 +++++++++++++++------------ app/routes/settings.profile.tsx | 12 +++++++----- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/app/routes/settings.account.tsx b/app/routes/settings.account.tsx index 820162e9..9d1b4272 100644 --- a/app/routes/settings.account.tsx +++ b/app/routes/settings.account.tsx @@ -456,9 +456,9 @@ export default function EditUserProfilePage() {

) : ( -
-

- +

+

+ {' '} {hasPendingEmail ? t('email_not_confirmed') @@ -470,6 +470,7 @@ export default function EditUserProfilePage() { type="button" variant="default" size="sm" + className="w-full sm:w-auto" disabled={resendFetcher.state === 'submitting'} onClick={() => { void resendFetcher.submit( @@ -495,8 +496,8 @@ export default function EditUserProfilePage() { ) : null}

-
-
+
+

{t('update_password')}

{t('update_password_description')} @@ -506,6 +507,7 @@ export default function EditUserProfilePage() {

-
-
+
+
Date: Thu, 13 Aug 2026 09:25:13 +0200 Subject: [PATCH 05/35] feat: padding, scroll tabs --- app/routes/settings.tsx | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/app/routes/settings.tsx b/app/routes/settings.tsx index 07e8ddef..f1a9833c 100644 --- a/app/routes/settings.tsx +++ b/app/routes/settings.tsx @@ -13,30 +13,32 @@ export default function SettingsLayoutPage() { return (
-
-
+
+
- - - {t('public_profile')} - +
+ + + {t('public_profile')} + - - {t('account')} - + + {t('account')} + - - {t('preferences')} - + + {t('preferences')} + - - {t('delete_account')} - - + + {t('delete_account')} + + +
From 77992954d826fc918df68f1c5e50f189b621eb41 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:25:31 +0200 Subject: [PATCH 06/35] feat: precautions for cms content --- app/components/markdown-content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/markdown-content.tsx b/app/components/markdown-content.tsx index 3968a2af..d85a3def 100644 --- a/app/components/markdown-content.tsx +++ b/app/components/markdown-content.tsx @@ -11,7 +11,7 @@ export function MarkdownContent({ }: MarkdownContentProps) { return (
Date: Thu, 13 Aug 2026 09:27:04 +0200 Subject: [PATCH 07/35] feat: split sidebar and content until lg, reduce mobile padding --- app/routes/profile.$username.tsx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/routes/profile.$username.tsx b/app/routes/profile.$username.tsx index 64613a36..edb78790 100644 --- a/app/routes/profile.$username.tsx +++ b/app/routes/profile.$username.tsx @@ -135,10 +135,10 @@ export default function ProfilePage() { return (
-
-
+
+
- + {profile?.profileImage?.id ? ( -
-

+
+

{profile?.displayName || ''}

-

+

{profile?.user?.name || ''}

@@ -193,9 +193,9 @@ export default function ProfilePage() {

-
-
-
+
+
+
{t('devices')}
@@ -213,8 +213,8 @@ export default function ProfilePage() {
{deviceSchemas.length > 0 && ( -
-
+
+
{t('device_schemas')}
From 98113bd7797defe0a893ccf39b7a8e99723b0671 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:30:25 +0200 Subject: [PATCH 08/35] feat: padding, shrinking --- app/routes/device.$deviceId.edit.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/routes/device.$deviceId.edit.tsx b/app/routes/device.$deviceId.edit.tsx index 30a44490..4bbe1c1f 100644 --- a/app/routes/device.$deviceId.edit.tsx +++ b/app/routes/device.$deviceId.edit.tsx @@ -89,7 +89,7 @@ export default function EditBox() { ] return ( -
+
{/*Toast notification */} @@ -139,8 +139,8 @@ export default function EditBox() {
-
-
+
+
{t('back_to_dashboard')}
From d0f6808164f4b66306087a2bf52d64c270bea428 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:31:47 +0200 Subject: [PATCH 09/35] feat: improve grid --- app/routes/device.$deviceId.edit.sensors.tsx | 34 +++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/routes/device.$deviceId.edit.sensors.tsx b/app/routes/device.$deviceId.edit.sensors.tsx index 4b541534..0f549681 100644 --- a/app/routes/device.$deviceId.edit.sensors.tsx +++ b/app/routes/device.$deviceId.edit.sensors.tsx @@ -368,11 +368,11 @@ export default function EditBoxSensors() { {/* Heading */}
{/* Title */} -
+

Sensor

-
+
{/* middle -> sensor attributes */} -
+
{/* shown by default */} {!sensor?.editing && ( @@ -585,10 +587,12 @@ export default function EditBoxSensors() { {sensor?.title} - + ID: -
- {sensor.id} +
+ + {sensor.id} + - -
- ) : ( - <> - - - - {t('forgot_your_password')} - - {t('reset_password')} - - -
- - - {actionData?.errors?.email && ( -
- {t(actionData.errors.email)} -
- )} -
-
- - -

- {t('remember_password')}{' '} - - {t('login_label')} - -

-
- - - )} - -
+ +
+ ) : ( + <> +
+ + + {t('forgot_your_password')} + + {t('reset_password')} + + +
+ + + {actionData?.errors?.email && ( +
+ {t(actionData.errors.email)} +
+ )} +
+
+ + +

+ {t('remember_password')}{' '} + + {t('login_label')} + +

+
+
+ + )} + +
+ ) } diff --git a/app/routes/explore.login.tsx b/app/routes/explore.login.tsx index 9a56de10..d47816ba 100644 --- a/app/routes/explore.login.tsx +++ b/app/routes/explore.login.tsx @@ -15,6 +15,7 @@ import { type Route } from './+types/explore.login' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import Spinner from '~/components/spinner' +import ViewportPortal from '~/components/viewport-portal' import { Button } from '~/components/ui/button' import { Card, @@ -143,106 +144,115 @@ export default function LoginPage() { }, []) return ( -
- -
- - - {navigation.state === 'loading' && ( -
- -
- )} -
- - - - {t('welcome_back')} - - {t('sign_in')} - - -
- - - {actionData?.errors?.identifier && ( -
- {t(actionData.errors.identifier)} -
- )} + +
+ +
+ + + {navigation.state === 'loading' && ( +
+
-
-
- - - {t('forgot_password')} - + )} + + + + + {t('welcome_back')} + + {t('sign_in')} + + +
+ + + {actionData?.errors?.identifier && ( +
+ {t(actionData.errors.identifier)} +
+ )}
- - {actionData?.errors?.password && ( -
- {t(actionData.errors.password)} +
+
+ + + {t('forgot_password')} +
- )} -
-
- - -
- - - -

- {t('no_account_label')}{' '} - - {t('register_label')} - -

-
- - -
+ + {actionData?.errors?.password && ( +
+ {t(actionData.errors.password)} +
+ )} +
+
+ + +
+ + + +

+ {t('no_account_label')}{' '} + + {t('register_label')} + +

+
+ + +
+ ) } diff --git a/app/routes/explore.register.tsx b/app/routes/explore.register.tsx index 4ef69a38..bc694fa7 100644 --- a/app/routes/explore.register.tsx +++ b/app/routes/explore.register.tsx @@ -16,6 +16,7 @@ import { Checkbox } from '@/components/ui/checkbox' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import Spinner from '~/components/spinner' +import ViewportPortal from '~/components/viewport-portal' import { Button } from '~/components/ui/button' import { Card, @@ -251,7 +252,41 @@ export default function RegisterDialog() { actionData.emailDeliveryFailed ) { return ( -
+ +
+ +
+ + + + + {t('account_created')} + + + {t('email_delivery_failed_description')} + + + + + + + + +
+ + ) + } + + return ( + +
- - - - {t('account_created')} - - - {t('email_delivery_failed_description')} - - - - - - - - -
- ) - } - - return ( -
- -
- - - {navigation.state === 'loading' && ( -
- -
- )} -
- - - {t('register')} - - {t('create_account')} - - -
- - -

- {t('username_hint')} -

- {actionErrors?.username && ( -
- {t(actionErrors?.username)} -
- )} -
-
- - - {actionErrors?.email && ( -
- {t(actionErrors?.email)} -
- )} + + {navigation.state === 'loading' && ( +
+
-
- - -

- {t('password_hint')} -

- {actionErrors?.password && ( -
- {t(actionErrors?.password)} + )} + + + + {t('register')} + + {t('create_account')} + + +
+ + +

+ {t('username_hint')} +

+ {actionErrors?.username && ( +
+ {t(actionErrors?.username)} +
+ )} +
+
+ + + {actionErrors?.email && ( +
+ {t(actionErrors?.email)} +
+ )} +
+
+ + +

+ {t('password_hint')} +

+ {actionErrors?.password && ( +
+ {t(actionErrors?.password)} +
+ )} +
+
+ + +
+
+ + +
+
+ +
+ + {actionErrors?.tosAccepted && ( +
+ {t(actionErrors?.tosAccepted)}
)} -
-
- - -
-
- - -
-
-
+ + + +
+ ) } From 45d1c9b49f69b97a0b52e36ec2367509187cc301 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:40:55 +0200 Subject: [PATCH 15/35] feat: responsive ui components --- app/components/ui/alert-dialog.tsx | 10 +++------- app/components/ui/dialog.tsx | 6 +++--- app/components/ui/drawer.tsx | 2 +- app/components/ui/sheet.tsx | 6 +++--- app/components/ui/table.tsx | 2 +- app/components/ui/tabs.tsx | 4 ++-- app/components/ui/toast.tsx | 12 ++++++------ 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/components/ui/alert-dialog.tsx b/app/components/ui/alert-dialog.tsx index 93bc1d66..ec3e1e67 100644 --- a/app/components/ui/alert-dialog.tsx +++ b/app/components/ui/alert-dialog.tsx @@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef< ) => (
(({ className, ...props }, ref) => ( )) diff --git a/app/components/ui/dialog.tsx b/app/components/ui/dialog.tsx index 3f64e51b..6d743f33 100644 --- a/app/components/ui/dialog.tsx +++ b/app/components/ui/dialog.tsx @@ -48,14 +48,14 @@ const DialogContent = React.forwardRef< {children} {!hideClose && ( - + Close @@ -85,7 +85,7 @@ const DialogFooter = ({ }: React.HTMLAttributes) => (
{children} - + Close @@ -98,7 +98,7 @@ const SheetFooter = ({ }: React.HTMLAttributes) => (
>(({ className, ...props }, ref) => ( -
+
(({ className, ...props }, ref) => ( )) @@ -105,7 +105,7 @@ const ToastDescription = React.forwardRef< >(({ className, ...props }, ref) => ( )) From 9e16adebc8bde63171ed9ae6e55b36ee556fe38c Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:43:52 +0200 Subject: [PATCH 16/35] feat: mobile header items --- app/components/header/home/index.tsx | 13 ++-- app/components/header/info/index.tsx | 13 ++-- app/components/header/menu/index.tsx | 94 +++++++++++++------------ app/components/header/nav-bar/index.tsx | 29 ++++++-- app/components/nav-bar.tsx | 21 +++--- 5 files changed, 101 insertions(+), 69 deletions(-) diff --git a/app/components/header/home/index.tsx b/app/components/header/home/index.tsx index 461b5468..275908b9 100644 --- a/app/components/header/home/index.tsx +++ b/app/components/header/home/index.tsx @@ -31,17 +31,22 @@ export default function Home({ aria-label={t('returnToGlobeView')} className={cn( topbarSurface({ shape: 'pill' }), - `pointer-events-auto flex cursor-pointer items-center gap-3 px-3 pr-4 focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 focus-visible:outline-hidden`, + `pointer-events-auto flex w-11 cursor-pointer items-center justify-center gap-3 px-2 focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 focus-visible:outline-hidden lg:w-auto lg:justify-start lg:px-3 lg:pr-4`, )} > openSenseMapLogo + {deviceCount > 0 && ( -
+

{deviceCount}{' '} diff --git a/app/components/header/info/index.tsx b/app/components/header/info/index.tsx index 052b8df2..617b5e7d 100644 --- a/app/components/header/info/index.tsx +++ b/app/components/header/info/index.tsx @@ -31,11 +31,14 @@ export default function Info() { return ( -

- -
+ (null) const navigation = useNavigation() const isLoggingOut = Boolean(navigation.state === 'submitting') @@ -56,15 +57,18 @@ export default function Menu({ devices }: MenuProps) { <> -
- -
+
@@ -84,11 +88,17 @@ export default function Menu({ devices }: MenuProps) {

) : ( -
-

+

+

{user?.name}

-

+

{user?.email}

@@ -168,12 +178,8 @@ export default function Menu({ devices }: MenuProps) { )} - { - e.preventDefault() - }} - > - {!user ? ( + {!user ? ( + setOpen(false)} className="w-full cursor-pointer" > - + + {t('login_label')} - ) : ( -
{ - setOpen(false) - toast({ - description: 'Successfully logged out.', - }) - }} +
+ ) : ( + { + setOpen(false) + toast({ + description: 'Successfully logged out.', + }) + }} + className="w-full cursor-pointer" + > + + { + event.preventDefault() + logoutFormRef.current?.requestSubmit() + }} > - - - - )} - + + {t('logout_label')} +
+ + )}
diff --git a/app/components/header/nav-bar/index.tsx b/app/components/header/nav-bar/index.tsx index 28604e74..0fb2ce8a 100644 --- a/app/components/header/nav-bar/index.tsx +++ b/app/components/header/nav-bar/index.tsx @@ -59,15 +59,30 @@ export default function NavBar(props: NavBarProps) { } }, [open]) - const isDesktop = useMediaQuery('(min-width: 768px)') + const isDesktop = useMediaQuery('(min-width: 1024px)') return ( -
+
+ + -
+
setOpen(true)} onChange={(e) => setSearchString(e.target.value)} - className="h-full w-full flex-1 border-none bg-transparent focus:border-none focus:ring-0 focus:outline-hidden dark:text-zinc-200" + className="h-full min-w-0 flex-1 border-none bg-transparent focus:border-none focus:ring-0 focus:outline-hidden dark:text-zinc-200" value={searchString} /> {!open && ( - + ctrl + K )} @@ -110,7 +125,7 @@ export default function NavBar(props: NavBarProps) { inputRef.current?.blur() }} aria-label="Close search" - className="rounded-full p-1 hover:bg-black/5 dark:hover:bg-white/10" + className="-mr-2 flex size-11 shrink-0 items-center justify-center rounded-full hover:bg-black/5 lg:mr-0 lg:size-8 dark:hover:bg-white/10" > diff --git a/app/components/nav-bar.tsx b/app/components/nav-bar.tsx index 951cf259..62ac213a 100644 --- a/app/components/nav-bar.tsx +++ b/app/components/nav-bar.tsx @@ -32,26 +32,29 @@ export function NavBar() { }) // prevents empty parts from showing return ( -
-
-
- +
+
+
+ osem Logo - + {parts.join(' / ')}
-
+
{user ? ( <> - @@ -77,12 +80,12 @@ export function NavBar() { -
+
) : ( -
+
-
+
-
+
-
+
-
+
diff --git a/app/components/mydevices/dt/data-table.tsx b/app/components/mydevices/dt/data-table.tsx index c232dd15..8d829326 100644 --- a/app/components/mydevices/dt/data-table.tsx +++ b/app/components/mydevices/dt/data-table.tsx @@ -79,7 +79,7 @@ export function DataTable({ const { t } = useTranslation('data-table') return ( -
+
({ />
-
+
{table.getHeaderGroups().map((headerGroup) => ( diff --git a/app/components/search/search-list-item.tsx b/app/components/search/search-list-item.tsx index 5128a35d..6a828aa2 100644 --- a/app/components/search/search-list-item.tsx +++ b/app/components/search/search-list-item.tsx @@ -17,7 +17,7 @@ interface SearchListItemProps } const searchListItemStyle = cva( - 'data-[active=true]:bg-light-green relative my-1 flex h-8 items-center gap-2 rounded-lg px-2 data-[active=true]:text-white', + 'data-[active=true]:bg-light-green relative my-1 flex min-h-11 cursor-pointer items-center gap-2 rounded-lg px-2 data-[active=true]:text-white md:h-8 md:min-h-0', { variants: { active: { @@ -44,10 +44,10 @@ export default function SearchListItem({ {index + 1} )} -
+
- + {name}
diff --git a/app/components/search/search-list.tsx b/app/components/search/search-list.tsx index 5ba9911e..66912024 100644 --- a/app/components/search/search-list.tsx +++ b/app/components/search/search-list.tsx @@ -126,7 +126,7 @@ export default function SearchList(props: SearchListProps) { }, [handleDigitPress]) return ( -
+
{props.searchResultsDevice.length > 0 && (
)} diff --git a/app/routes/about.tsx b/app/routes/about.tsx index b244a021..5b6c324e 100644 --- a/app/routes/about.tsx +++ b/app/routes/about.tsx @@ -105,10 +105,10 @@ export default function Index() { const { t } = useTranslation('landing') - const isDesktop = useMediaQuery('(min-width: 768px)') + const showGlobe = useMediaQuery('(min-width: 1120px)') return ( -
+
@@ -118,7 +118,7 @@ export default function Index() { className="mx-auto flex max-w-7xl flex-col justify-center px-4 sm:px-6 lg:px-8" >
-
+
-

+

openSenseMap

@@ -136,11 +136,11 @@ export default function Index() { animate={{ opacity: 1, x: 0 }} transition={{ ease: 'easeInOut', duration: 0.5 }} > -

+

{t('introduction')}

-
+
- {isDesktop && ( -
+ {showGlobe && ( +
)}
- {isDesktop && ( -
- -
- )} +
+ +
{sections.map((section, _index) => { const Component = section.component return (
) })} -
+
diff --git a/app/routes/account.password-reset.tsx b/app/routes/account.password-reset.tsx index 7700854d..53ecc739 100644 --- a/app/routes/account.password-reset.tsx +++ b/app/routes/account.password-reset.tsx @@ -143,7 +143,7 @@ export default function PasswordResetRoute() { if (!token) { return ( -
+
- + {t('reset_link_invalid_title')} @@ -168,7 +168,7 @@ export default function PasswordResetRoute() { {t('back_to_login')} - + @@ -180,7 +180,7 @@ export default function PasswordResetRoute() { } return ( -
+
- + {busy && (
@@ -292,7 +292,7 @@ export default function PasswordResetRoute() { {t('set_password_button')} -

+

{t('remember_password')}{' '} +

{/* Left side - device info */} -
- +
+ - {deviceData.name} - {deviceData._id} + + {deviceData.name} + + + {deviceData._id} + {/* properties */} @@ -152,7 +156,7 @@ export default function DeviceDashboard() { alt={'name'} width={250} height={330} - className="h-auto w-auto object-cover transition-all hover:scale-105" + className="h-auto w-full object-cover transition-all hover:scale-105" />

@@ -187,9 +191,9 @@ export default function DeviceDashboard() { {/* Right side - measurements */} - + -

+
{deviceData.sensors.map((sensor: any) => ( +
-
-
-
+
+
+
diff --git a/app/routes/device.transfer.tsx b/app/routes/device.transfer.tsx index eee3c84e..e3b495cb 100644 --- a/app/routes/device.transfer.tsx +++ b/app/routes/device.transfer.tsx @@ -61,7 +61,7 @@ export default function DeviceTransfer() {
-
+
{t('back_to_dashboard')} @@ -93,7 +93,7 @@ export default function DeviceTransfer() { diff --git a/app/routes/imprint.tsx b/app/routes/imprint.tsx index 87125cd6..ceb20c8f 100644 --- a/app/routes/imprint.tsx +++ b/app/routes/imprint.tsx @@ -73,8 +73,8 @@ export default function Imprint({ return ( <>
-
-
-

{title}

+
+

{title}

{content}
diff --git a/app/routes/privacy.tsx b/app/routes/privacy.tsx index b23667ba..c5386c63 100644 --- a/app/routes/privacy.tsx +++ b/app/routes/privacy.tsx @@ -73,8 +73,8 @@ export default function Privacy({ return ( <>
-
-
-

{title}

+
+

{title}

{content}
From ae1472fd7b324c71d03a8450a9d220bec0ad3821 Mon Sep 17 00:00:00 2001 From: jona159 Date: Thu, 13 Aug 2026 09:47:59 +0200 Subject: [PATCH 19/35] fix: wrap tooltip provider --- .../landing/header/language-selector.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/app/components/landing/header/language-selector.tsx b/app/components/landing/header/language-selector.tsx index 048d9999..f1d9181a 100644 --- a/app/components/landing/header/language-selector.tsx +++ b/app/components/landing/header/language-selector.tsx @@ -4,6 +4,7 @@ import { Button } from '~/components/ui/button' import { Tooltip, TooltipContent, + TooltipProvider, TooltipTrigger, } from '~/components/ui/tooltip' import { useRootRouteLoaderData } from '~/root' @@ -25,20 +26,23 @@ export default function LanguageSelector() { const nextLanguageLabel = locale === 'de' ? 'English' : 'Deutsch' return ( - - - - + + + + + - {languageLabel} - + {languageLabel} + + ) } From 983c734b46b44825f9086b41730a5e02eb2812f6 Mon Sep 17 00:00:00 2001 From: jona159 Date: Fri, 21 Aug 2026 08:22:15 +0200 Subject: [PATCH 20/35] feat: replace dependency --- app/components/header/nav-bar/index.tsx | 7 ++----- app/routes/about.tsx | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/app/components/header/nav-bar/index.tsx b/app/components/header/nav-bar/index.tsx index 0fb2ce8a..631a599f 100644 --- a/app/components/header/nav-bar/index.tsx +++ b/app/components/header/nav-bar/index.tsx @@ -1,4 +1,3 @@ -import { useMediaQuery } from '@mantine/hooks' import { AnimatePresence, motion } from 'framer-motion' import { SearchIcon, XIcon } from 'lucide-react' import { useState, useEffect, useRef, createContext } from 'react' @@ -59,8 +58,6 @@ export default function NavBar(props: NavBarProps) { } }, [open]) - const isDesktop = useMediaQuery('(min-width: 1024px)') - return (
From 8268912d91e78de745ff1b77e1b7aa52b52c1714 Mon Sep 17 00:00:00 2001 From: jona159 Date: Fri, 21 Aug 2026 15:16:14 +0200 Subject: [PATCH 21/35] feat: show entry logs in dialog on all screens to remove mantine dependency --- app/components/device-detail/entry-logs.tsx | 125 ++++++-------------- 1 file changed, 38 insertions(+), 87 deletions(-) diff --git a/app/components/device-detail/entry-logs.tsx b/app/components/device-detail/entry-logs.tsx index 259d15af..b1548aef 100644 --- a/app/components/device-detail/entry-logs.tsx +++ b/app/components/device-detail/entry-logs.tsx @@ -1,4 +1,3 @@ -import { useMediaQuery } from '@mantine/hooks' import { Activity, Clock, ExternalLink } from 'lucide-react' import { useState } from 'react' import { useTranslation } from 'react-i18next' @@ -11,16 +10,6 @@ import { DialogTitle, DialogTrigger, } from '../ui/dialog' -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerDescription, - DrawerFooter, - DrawerHeader, - DrawerTitle, - DrawerTrigger, -} from '../ui/drawer' import { Tooltip, TooltipContent, @@ -37,95 +26,57 @@ export default function EntryLogs({ entryLogs: LogEntry[] }) { const [open, setOpen] = useState(false) - const isDesktop = useMediaQuery('(min-width: 768px)') const { t, i18n } = useTranslation('device-detail-box') + const latestEntry = entryLogs.at(-1) - if (isDesktop) { - return ( -
-

{t('logs')}

-
-
-
- -
-
-

- {entryLogs[entryLogs.length - 1].content} -

-
- - {new Date(entryLogs[0].createdAt).toLocaleString(i18n.language)} -
-
-
-
- - - - - - - {t('device_logs')} - {t('logs_owner_hint')} - - - - -
-
-
- ) - } + if (!latestEntry) return null return (

{t('logs')}

-
-
-
- +
+
+
+
-
-

{entryLogs[0].content}

+
+

+ {latestEntry.content} +

- {new Date(entryLogs[0].createdAt).toLocaleString(i18n.language)} + {new Date(latestEntry.createdAt).toLocaleString(i18n.language)}
-
- - - - - - - {t('device_logs')} - {t('logs_owner_hint')} - + + + + + + + + + +

{t('show_all_logs')}

+
+
+
+ + + {t('device_logs')} + {t('logs_owner_hint')} + - - - - - -
-
+ +
) From 58ec6c743af17f80d26c5366f802b9c7fcf19e62 Mon Sep 17 00:00:00 2001 From: jona159 Date: Fri, 21 Aug 2026 15:16:48 +0200 Subject: [PATCH 22/35] chore: rm mantine --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 607eddfd..efd1a9e6 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@formatjs/intl": "^4.1.18", "@heroicons/react": "^2.2.0", "@hookform/resolvers": "^5.4.0", - "@mantine/hooks": "^9.2.1", "@maplibre/maplibre-gl-geocoder": "^1.9.4", "@mjackson/form-data-parser": "^0.9.1", "@paralleldrive/cuid2": "^3.3.0", From 7451e58f090a0b99019fe93445c89f67cec8e85d Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 09:17:00 +0200 Subject: [PATCH 23/35] fix: use https url --- app/components/landing/sections/pricing-plans.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/landing/sections/pricing-plans.tsx b/app/components/landing/sections/pricing-plans.tsx index 76105457..f4010933 100644 --- a/app/components/landing/sections/pricing-plans.tsx +++ b/app/components/landing/sections/pricing-plans.tsx @@ -17,7 +17,7 @@ export default function PricingPlans() {
Date: Mon, 24 Aug 2026 09:34:56 +0200 Subject: [PATCH 24/35] fix: revert styling for edge cases# --- app/components/device-detail/graph.tsx | 2 +- app/components/error-message.tsx | 6 +- app/components/header/info/index.tsx | 13 +-- app/components/header/menu/index.tsx | 94 +++++++++---------- .../landing/header/language-selector.tsx | 32 +++---- .../landing/header/theme-toggle.tsx | 1 - app/components/landing/stats.tsx | 8 +- app/components/language-select.tsx | 2 +- app/components/map/legend.tsx | 8 +- app/components/markdown-content.tsx | 2 +- app/components/nav-bar.tsx | 21 ++--- app/components/search/search-list-item.tsx | 6 +- app/components/theme-select.tsx | 2 +- app/components/ui/alert-dialog.tsx | 10 +- app/components/ui/drawer.tsx | 2 +- app/components/ui/sheet.tsx | 6 +- app/components/ui/toast.tsx | 12 +-- app/root.tsx | 2 +- app/routes/imprint.tsx | 8 +- app/routes/privacy.tsx | 8 +- 20 files changed, 115 insertions(+), 130 deletions(-) diff --git a/app/components/device-detail/graph.tsx b/app/components/device-detail/graph.tsx index 75af724a..2186a98f 100644 --- a/app/components/device-detail/graph.tsx +++ b/app/components/device-detail/graph.tsx @@ -556,7 +556,7 @@ export default function Graph({ >
{navigation.state === 'loading' && (
diff --git a/app/components/error-message.tsx b/app/components/error-message.tsx index 57b7a380..d340919b 100644 --- a/app/components/error-message.tsx +++ b/app/components/error-message.tsx @@ -155,7 +155,7 @@ export default function ErrorMessage() { } return ( -
+
@@ -169,9 +169,7 @@ export default function ErrorMessage() {

)} {title} - - {message} - + {message} diff --git a/app/components/header/info/index.tsx b/app/components/header/info/index.tsx index 617b5e7d..052b8df2 100644 --- a/app/components/header/info/index.tsx +++ b/app/components/header/info/index.tsx @@ -31,14 +31,11 @@ export default function Info() { return ( - +
+ +
(null) const navigation = useNavigation() const isLoggingOut = Boolean(navigation.state === 'submitting') @@ -57,18 +56,15 @@ export default function Menu({ devices }: MenuProps) { <> - +
+ +
@@ -88,17 +84,11 @@ export default function Menu({ devices }: MenuProps) {

) : ( -
-

+

+

{user?.name}

-

+

{user?.email}

@@ -178,8 +168,12 @@ export default function Menu({ devices }: MenuProps) { )} - {!user ? ( - + { + e.preventDefault() + }} + > + {!user ? ( setOpen(false)} className="w-full cursor-pointer" > - - {t('login_label')} + - - ) : ( - { - setOpen(false) - toast({ - description: 'Successfully logged out.', - }) - }} - className="w-full cursor-pointer" - > - - { - event.preventDefault() - logoutFormRef.current?.requestSubmit() + ) : ( + { + setOpen(false) + toast({ + description: 'Successfully logged out.', + }) }} + className="w-full cursor-pointer" > - - {t('logout_label')} - - - )} + + + + )} +
diff --git a/app/components/landing/header/language-selector.tsx b/app/components/landing/header/language-selector.tsx index f1d9181a..048d9999 100644 --- a/app/components/landing/header/language-selector.tsx +++ b/app/components/landing/header/language-selector.tsx @@ -4,7 +4,6 @@ import { Button } from '~/components/ui/button' import { Tooltip, TooltipContent, - TooltipProvider, TooltipTrigger, } from '~/components/ui/tooltip' import { useRootRouteLoaderData } from '~/root' @@ -26,23 +25,20 @@ export default function LanguageSelector() { const nextLanguageLabel = locale === 'de' ? 'English' : 'Deutsch' return ( - - - - - + + + + - {languageLabel} - - + {languageLabel} + ) } diff --git a/app/components/landing/header/theme-toggle.tsx b/app/components/landing/header/theme-toggle.tsx index 358f4069..cfda60a6 100644 --- a/app/components/landing/header/theme-toggle.tsx +++ b/app/components/landing/header/theme-toggle.tsx @@ -59,7 +59,6 @@ export default function ThemeToggle() { @@ -80,12 +77,12 @@ export function NavBar() { -
+
) : ( -
+
)} -
+
- + {name}
diff --git a/app/components/theme-select.tsx b/app/components/theme-select.tsx index 3ec96ab0..8a5bd3d5 100644 --- a/app/components/theme-select.tsx +++ b/app/components/theme-select.tsx @@ -76,7 +76,7 @@ export function ThemeSelect() { ) }} > - + diff --git a/app/components/ui/alert-dialog.tsx b/app/components/ui/alert-dialog.tsx index ec3e1e67..93bc1d66 100644 --- a/app/components/ui/alert-dialog.tsx +++ b/app/components/ui/alert-dialog.tsx @@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef< ) => (
(({ className, ...props }, ref) => ( )) diff --git a/app/components/ui/drawer.tsx b/app/components/ui/drawer.tsx index 72ae15d5..16a65ca1 100644 --- a/app/components/ui/drawer.tsx +++ b/app/components/ui/drawer.tsx @@ -43,7 +43,7 @@ const DrawerContent = React.forwardRef< {children} - + Close @@ -98,7 +98,7 @@ const SheetFooter = ({ }: React.HTMLAttributes) => (
(({ className, ...props }, ref) => ( )) @@ -105,7 +105,7 @@ const ToastDescription = React.forwardRef< >(({ className, ...props }, ref) => ( )) diff --git a/app/root.tsx b/app/root.tsx index 368ee385..36fad1e5 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -272,7 +272,7 @@ export function ErrorBoundary() { {meta()} -
+
diff --git a/app/routes/imprint.tsx b/app/routes/imprint.tsx index ceb20c8f..87125cd6 100644 --- a/app/routes/imprint.tsx +++ b/app/routes/imprint.tsx @@ -73,8 +73,8 @@ export default function Imprint({ return ( <>
-
-
-

{title}

+
+

{title}

{content}
diff --git a/app/routes/privacy.tsx b/app/routes/privacy.tsx index c5386c63..b23667ba 100644 --- a/app/routes/privacy.tsx +++ b/app/routes/privacy.tsx @@ -73,8 +73,8 @@ export default function Privacy({ return ( <>
-
-
-

{title}

+
+

{title}

{content}
From 5b38902742ea4d2c3502833853fb016747ac636d Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 09:38:23 +0200 Subject: [PATCH 25/35] fix: accessibility --- app/components/landing/header/header.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/components/landing/header/header.tsx b/app/components/landing/header/header.tsx index d04a6ec4..f3c2d67e 100644 --- a/app/components/landing/header/header.tsx +++ b/app/components/landing/header/header.tsx @@ -85,14 +85,17 @@ export default function Header() { {/* Collapsible navigation bar */}
From 1923a7740f7a0c7a26eb2cbdb9c7976602651658 Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 09:45:45 +0200 Subject: [PATCH 28/35] fix: wrap long localized labels on mobile --- app/routes/settings.preferences.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/settings.preferences.tsx b/app/routes/settings.preferences.tsx index d72a7a1d..9522f2f9 100644 --- a/app/routes/settings.preferences.tsx +++ b/app/routes/settings.preferences.tsx @@ -638,7 +638,7 @@ export default function PreferencesSettingsPage() {
-
+
Date: Mon, 24 Aug 2026 11:27:37 +0200 Subject: [PATCH 29/35] fix: rm unnecessary custom data attribute --- app/components/landing/header/header.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/landing/header/header.tsx b/app/components/landing/header/header.tsx index f3c2d67e..f6df9cd1 100644 --- a/app/components/landing/header/header.tsx +++ b/app/components/landing/header/header.tsx @@ -87,7 +87,6 @@ export default function Header() { + +
+ ) : ( + <> +
+ + + {t('forgot_your_password')} + + {t('reset_password')} + + +
+ + + {actionData?.errors?.email && ( +
+ {t(actionData.errors.email)} +
+ )} +
+
+ + - -
- ) : ( - <> - - - - {t('forgot_your_password')} - - {t('reset_password')} - - -
- - - {actionData?.errors?.email && ( -
- {t(actionData.errors.email)} -
- )} -
-
- - -

- {t('remember_password')}{' '} - - {t('login_label')} - -

-
- - - )} - -
- +

+ {t('remember_password')}{' '} + + {t('login_label')} + +

+ + + + )} + +
) } diff --git a/app/routes/explore.login.tsx b/app/routes/explore.login.tsx index 095a9448..04ca6cd3 100644 --- a/app/routes/explore.login.tsx +++ b/app/routes/explore.login.tsx @@ -14,7 +14,6 @@ import { type Route } from './+types/explore.login' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import Spinner from '~/components/spinner' -import ViewportPortal from '~/components/viewport-portal' import { Button } from '~/components/ui/button' import { Card, @@ -139,115 +138,106 @@ export default function LoginPage() { }, []) return ( - -
- -
- - - {navigation.state === 'loading' && ( -
- +
+ +
+ + + {navigation.state === 'loading' && ( +
+ +
+ )} +
+ + + + {t('welcome_back')} + + {t('sign_in')} + + +
+ + + {actionData?.errors?.identifier && ( +
+ {t(actionData.errors.identifier)} +
+ )}
- )} - - - - - {t('welcome_back')} - - {t('sign_in')} - - -
- - - {actionData?.errors?.identifier && ( -
- {t(actionData.errors.identifier)} -
- )} +
+
+ + + {t('forgot_password')} +
-
-
- - - {t('forgot_password')} - + + {actionData?.errors?.password && ( +
+ {t(actionData.errors.password)}
- - {actionData?.errors?.password && ( -
- {t(actionData.errors.password)} -
- )} -
-
- - -
- - - -

- {t('no_account_label')}{' '} - - {t('register_label')} - -

-
- - -
- + )} +
+
+ + +
+ + + +

+ {t('no_account_label')}{' '} + + {t('register_label')} + +

+
+ + +
) } diff --git a/app/routes/explore.register.tsx b/app/routes/explore.register.tsx index 6d21c2f9..788a40c8 100644 --- a/app/routes/explore.register.tsx +++ b/app/routes/explore.register.tsx @@ -15,7 +15,6 @@ import { Checkbox } from '@/components/ui/checkbox' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import Spinner from '~/components/spinner' -import ViewportPortal from '~/components/viewport-portal' import { Button } from '~/components/ui/button' import { Card, @@ -247,199 +246,189 @@ export default function RegisterDialog() { actionData.emailDeliveryFailed ) { return ( - -
- -
- - - - - {t('account_created')} - - - {t('email_delivery_failed_description')} - - - - - - - - -
- - ) - } - - return ( - -
+
-
+
- {navigation.state === 'loading' && ( -
- -
- )} -
- - - {t('register')} - - {t('create_account')} - - -
- - -

- {t('username_hint')} -

- {actionErrors?.username && ( -
- {t(actionErrors?.username)} -
- )} -
-
- - - {actionErrors?.email && ( -
- {t(actionErrors?.email)} -
- )} -
-
- - -

- {t('password_hint')} -

- {actionErrors?.password && ( -
- {t(actionErrors?.password)} -
- )} -
-
- - -
-
- - -
-
- -
+ + + {t('account_created')} + + + {t('email_delivery_failed_description')} + + + + + + + +
+
+ ) + } - {actionErrors?.tosAccepted && ( -
- {t(actionErrors?.tosAccepted)} + return ( +
+ +
+ + + {navigation.state === 'loading' && ( +
+ +
+ )} + + + + {t('register')} + + {t('create_account')} + + +
+ + +

+ {t('username_hint')} +

+ {actionErrors?.username && ( +
+ {t(actionErrors?.username)} +
+ )} +
+
+ + + {actionErrors?.email && ( +
+ {t(actionErrors?.email)}
)} - - - -
- {t('already_account')}{' '} - - {t('login')} +
+
+ + +

+ {t('password_hint')} +

+ {actionErrors?.password && ( +
+ {t(actionErrors?.password)} +
+ )} +
+
+ + +
+
+ + +
+
+ +
+ + {actionErrors?.tosAccepted && ( +
+ {t(actionErrors?.tosAccepted)}
-
- - -
- + )} +
+ + +
+ {t('already_account')}{' '} + + {t('login')} + +
+
+ +
+
) } diff --git a/app/routes/explore.tsx b/app/routes/explore.tsx index e9e31a58..ac522637 100644 --- a/app/routes/explore.tsx +++ b/app/routes/explore.tsx @@ -9,7 +9,7 @@ import { type MapInstance, } from 'react-map-gl/maplibre' import { - Outlet, + useOutlet, useNavigate, useSearchParams, useLoaderData, @@ -423,6 +423,7 @@ export default function Explore() { const appliedInitialMyAreaRef = useRef(false) const navigate = useNavigate() const location = useLocation() + const outlet = useOutlet() const [selectedPheno, setSelectedPheno] = useState(undefined) const [searchParams] = useSearchParams() const [filteredData, setFilteredData] = useState< @@ -924,11 +925,11 @@ export default function Explore() { /> )} -
-
- + {outlet && ( +
+
{outlet}
-
+ )}
From 29b674d5ffdffad1e61a19f732d8e6a7b19f1eb7 Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 13:13:33 +0200 Subject: [PATCH 31/35] fix: return ordered entry logs --- app/components/device-detail/entry-logs.tsx | 2 +- app/db/models/device.server.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/components/device-detail/entry-logs.tsx b/app/components/device-detail/entry-logs.tsx index b1548aef..f7e3423c 100644 --- a/app/components/device-detail/entry-logs.tsx +++ b/app/components/device-detail/entry-logs.tsx @@ -27,7 +27,7 @@ export default function EntryLogs({ }) { const [open, setOpen] = useState(false) const { t, i18n } = useTranslation('device-detail-box') - const latestEntry = entryLogs.at(-1) + const latestEntry = entryLogs[0] if (!latestEntry) return null diff --git a/app/db/models/device.server.ts b/app/db/models/device.server.ts index ba1c7219..ba166ae9 100644 --- a/app/db/models/device.server.ts +++ b/app/db/models/device.server.ts @@ -117,6 +117,7 @@ export function getDevice({ id }: Pick) { }, logEntries: { where: (entry, { eq }) => eq(entry.public, true), + orderBy: (entry, { desc }) => [desc(entry.createdAt)], columns: { id: true, content: true, From 6dbef8107089137e1b047df456822dc870c1418d Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 13:13:47 +0200 Subject: [PATCH 32/35] fix: regenerate lock file --- package-lock.json | 191 +++++++++++++++++----------------------------- 1 file changed, 68 insertions(+), 123 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86a8791a..dfe7c0d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "@formatjs/intl": "^4.1.18", "@heroicons/react": "^2.2.0", "@hookform/resolvers": "^5.4.0", - "@mantine/hooks": "^9.2.1", "@maplibre/maplibre-gl-geocoder": "^1.9.4", "@mjackson/form-data-parser": "^0.9.1", "@paralleldrive/cuid2": "^3.3.0", @@ -568,6 +567,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1216,6 +1216,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" }, @@ -1264,6 +1265,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" } @@ -1272,7 +1274,8 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.5.0.tgz", "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@daypicker/react": { "version": "10.0.1", @@ -1325,7 +1328,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" @@ -1338,18 +1340,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "dev": true, - "license": "MIT", - "optional": true, "dependencies": { "tslib": "^2.4.0" } @@ -2977,15 +2967,6 @@ "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", "license": "MIT" }, - "node_modules/@mantine/hooks": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-9.4.2.tgz", - "integrity": "sha512-1SUuhnbvcV7EfwYN2FcdI9nX2TXhQQMefR7uWsigdor+2Twk0yEKMKct8t9gw6PQtkWF9GZxkg8aJRA3KmhaSA==", - "license": "MIT", - "peerDependencies": { - "react": "^19.2.0" - } - }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz", @@ -3371,6 +3352,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -4064,6 +4046,7 @@ "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "playwright": "1.61.1" }, @@ -5625,6 +5608,7 @@ "integrity": "sha512-XR+N2fEFOPjczYo2efc3/AOtosbSICCroLF/IxnZ6ErGBeBGRG6SqAso0SYoff0e18OA05qOyhJHFhXKMGIPRw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.29.7", "@babel/generator": "^7.29.7", @@ -5756,6 +5740,7 @@ "resolved": "https://registry.npmjs.org/@react-router/serve/-/serve-8.3.0.tgz", "integrity": "sha512-ILFhPizuaNtQKfX1aLg6lr7r5FMZO/DgerUpGFhnK85t7M5c6ZNOb7VUURlJpu/ArUR2Sh+f5nBYTsgFt2R2OA==", "license": "MIT", + "peer": true, "dependencies": { "@react-router/express": "8.3.0", "@react-router/node": "8.3.0", @@ -5805,6 +5790,7 @@ "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.7.1.tgz", "integrity": "sha512-6goBapMwyHcXvjLkCnFs4S3P1oKUi1H083BdPk4pDZALFWn5ZdG50ECNfHSddBmL3O0pyx1/WFq1C/MuR7Y54A==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@x0k/json-schema-merge": "^1.0.3", "fast-equals": "^6.0.0", @@ -6137,8 +6123,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.62.2", @@ -6151,8 +6136,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.62.2", @@ -6165,8 +6149,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.62.2", @@ -6179,8 +6162,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.62.2", @@ -6193,8 +6175,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.62.2", @@ -6207,8 +6188,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.62.2", @@ -6221,8 +6201,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.62.2", @@ -6235,8 +6214,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.62.2", @@ -6249,8 +6227,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.62.2", @@ -6263,8 +6240,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.62.2", @@ -6277,8 +6253,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.62.2", @@ -6291,8 +6266,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.62.2", @@ -6305,8 +6279,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.62.2", @@ -6319,8 +6292,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.62.2", @@ -6333,8 +6305,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.62.2", @@ -6347,8 +6318,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.62.2", @@ -6361,8 +6331,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.62.2", @@ -6375,8 +6344,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.62.2", @@ -6389,8 +6357,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.62.2", @@ -6403,8 +6370,7 @@ "optional": true, "os": [ "openbsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.62.2", @@ -6417,8 +6383,7 @@ "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.62.2", @@ -6431,8 +6396,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.62.2", @@ -6445,8 +6409,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.62.2", @@ -6459,8 +6422,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.62.2", @@ -6473,8 +6435,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rvf/set-get": { "version": "7.0.3", @@ -7276,18 +7237,6 @@ } } }, - "node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2/node_modules/tree-sitter": { - "version": "0.22.4", - "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz", - "integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-addon-api": "^8.3.0", - "node-gyp-build": "^4.8.4" - } - }, "node_modules/@swagger-api/apidom-reference": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.12.0.tgz", @@ -7604,27 +7553,6 @@ "node": ">=14.0.0" } }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "dev": true, @@ -7771,6 +7699,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -8084,6 +8013,7 @@ "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -8111,6 +8041,7 @@ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -8121,6 +8052,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -8282,6 +8214,7 @@ "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.10", @@ -8411,6 +8344,7 @@ "integrity": "sha512-EOUqfXHTXtpSHsyLHH40ts3Ue+hRhSGwzwzMlK0dTEOLSDYyOXLyr5JDGmHQWhN2DYI30gw6dVx3cdgM9FZl+Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/utils": "4.1.10", "fflate": "^0.8.2", @@ -8939,6 +8873,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.44", "caniuse-lite": "^1.0.30001806", @@ -9168,6 +9103,7 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", "license": "MIT", + "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -9886,6 +9822,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -11296,6 +11233,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -12217,6 +12155,7 @@ } ], "license": "MIT", + "peer": true, "peerDependencies": { "typescript": "^5 || ^6 || ^7" }, @@ -12290,7 +12229,8 @@ "version": "4.3.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.9.tgz", "integrity": "sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/indent-string": { "version": "4.0.0", @@ -13640,6 +13580,7 @@ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz", "integrity": "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/point-geometry": "^1.1.0", @@ -14504,6 +14445,7 @@ "integrity": "sha512-CopwJOwPAjZ9p76fCvz+mSOJTw9/NY3cSksZK3VO/bUQ8UoEcketNgUuYS0UB3p+R9XnXe7wGGXUmyFxc7QxJA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "tinypool": "2.1.0" }, @@ -14767,6 +14709,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz", "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", @@ -14863,6 +14806,7 @@ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -15024,6 +14968,7 @@ "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.9.tgz", "integrity": "sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==", "license": "Unlicense", + "peer": true, "engines": { "node": ">=12" }, @@ -15355,6 +15300,7 @@ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", "integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/ramda" @@ -15431,6 +15377,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -15502,6 +15449,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -15655,6 +15603,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.85.0.tgz", "integrity": "sha512-U2MTriFXnclmV4rOE20p2DcRFv5WEg3FIcBFOKcOLFHDVvGIMPvLTkTWefUsonmlaVy23khVDxDWym6uJVGOzw==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -15846,6 +15795,7 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-8.3.0.tgz", "integrity": "sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==", "license": "MIT", + "peer": true, "dependencies": { "cookie-es": "^3.1.1" }, @@ -15951,7 +15901,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-immutable": { "version": "4.0.0", @@ -17477,7 +17428,8 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -17515,7 +17467,8 @@ "version": "0.185.1", "resolved": "https://registry.npmjs.org/three/-/three-0.185.1.tgz", "integrity": "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/three-conic-polygon-geometry": { "version": "2.1.3", @@ -17778,18 +17731,6 @@ "node": ">=20" } }, - "node_modules/tree-sitter": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz", - "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-addon-api": "^8.0.0", - "node-gyp-build": "^4.8.0" - } - }, "node_modules/tree-sitter-json": { "version": "0.24.8", "resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.24.8.tgz", @@ -18014,6 +17955,7 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18317,6 +18259,7 @@ "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", @@ -18439,6 +18382,7 @@ "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.1.10", "@vitest/mocker": "4.1.10", @@ -18895,6 +18839,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } From 63e019dbc8d772f51284c88b49ba0e73e70aea3d Mon Sep 17 00:00:00 2001 From: jona159 Date: Mon, 24 Aug 2026 13:19:11 +0200 Subject: [PATCH 33/35] fix: rm ring opacity as unsupported in tw v4 --- app/components/landing/header/header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/landing/header/header.tsx b/app/components/landing/header/header.tsx index f6df9cd1..3256b71d 100644 --- a/app/components/landing/header/header.tsx +++ b/app/components/landing/header/header.tsx @@ -112,7 +112,7 @@ export default function Header() { {openMenu && (
- + {showGlobe && }
From 1b69b2cada02641bb031f77cbf5e19563650361f Mon Sep 17 00:00:00 2001 From: David Scheidt Date: Fri, 28 Aug 2026 10:59:30 +0200 Subject: [PATCH 35/35] optimize graph filter arrangement on mobile --- app/components/aggregation-filter.tsx | 4 ++-- app/components/device-detail/graph.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/aggregation-filter.tsx b/app/components/aggregation-filter.tsx index 8b780e9b..eed726a9 100644 --- a/app/components/aggregation-filter.tsx +++ b/app/components/aggregation-filter.tsx @@ -57,10 +57,10 @@ export function AggregationFilter() { > -
+
Aggregation <> diff --git a/app/components/device-detail/graph.tsx b/app/components/device-detail/graph.tsx index 1852dbdb..a8bfc7a3 100644 --- a/app/components/device-detail/graph.tsx +++ b/app/components/device-detail/graph.tsx @@ -558,14 +558,14 @@ export default function Graph({
)}
-
+
{currentZoom !== null && currentZoom.xMax !== 0 && currentZoom.xMin !== 0 && (