From d189d75d5d062c9618933288c84f6676f3dad00e Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Sun, 11 Jan 2026 15:54:08 -0500 Subject: [PATCH] fix: resolve random css issues with mobile layouts --- CHANGELOG.md | 1 + app/components/Tabs.tsx | 10 +- app/root.tsx | 2 +- app/routes/dns/components/manage-domains.tsx | 46 +-- app/routes/dns/components/manage-ns.tsx | 35 +- app/routes/dns/components/manage-records.tsx | 24 +- app/routes/dns/components/rename-tailnet.tsx | 14 +- app/routes/dns/overview.tsx | 12 +- app/routes/machines/overview.tsx | 302 +++++++++--------- app/routes/settings/overview.tsx | 6 +- app/routes/settings/restrictions/overview.tsx | 2 +- app/routes/settings/restrictions/table.tsx | 4 +- app/routes/users/overview.tsx | 54 ++-- app/tailwind.css | 1 + 14 files changed, 261 insertions(+), 252 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce30d1e..5ab1897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Added an `/admin/api/info` route that can expose sensitive information if `server.info_secret` is set in the configuration (closes [#324](https://github.com/tale/headplane/issues/324)). - Correctly apply Gravatar profile pictures on the user page if applicable (closes [#405](https://github.com/tale/headplane/issues/405)). - Machine key registration no longer works if the key isn't 24 characters long (closes [#415](https://github.com/tale/headplane/issues/415)). +- Fixed some mobile CSS issues across the application (closes [#401](https://github.com/tale/headplane/issues/401)). --- # 0.6.1 (October 12, 2025) diff --git a/app/components/Tabs.tsx b/app/components/Tabs.tsx index d135d09..710a419 100644 --- a/app/components/Tabs.tsx +++ b/app/components/Tabs.tsx @@ -23,15 +23,15 @@ function Tabs({ label, className, ...props }: TabsProps) {
{[...state.collection].map((item) => ( - + ))}
@@ -52,7 +52,6 @@ function Tab({ item, state }: TabsTabProps) { return (
{rendered}
@@ -76,11 +76,11 @@ function TabsPanel({ state, ...props }: TabsPanelProps) { return (
{state.selectedItem?.props.children}
diff --git a/app/root.tsx b/app/root.tsx index 17b95e8..c4b6918 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -45,7 +45,7 @@ export function Layout({ children }: { readonly children: React.ReactNode }) { - + {children} diff --git a/app/routes/dns/components/manage-domains.tsx b/app/routes/dns/components/manage-domains.tsx index 5cd47e4..abc5a89 100644 --- a/app/routes/dns/components/manage-domains.tsx +++ b/app/routes/dns/components/manage-domains.tsx @@ -1,18 +1,18 @@ -import { DndContext, DragOverlay, closestCorners } from '@dnd-kit/core'; +import { closestCorners, DndContext, DragOverlay } from '@dnd-kit/core'; import { restrictToParentElement, restrictToVerticalAxis, } from '@dnd-kit/modifiers'; import { - SortableContext, arrayMove, + SortableContext, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import { GripVertical, Lock } from 'lucide-react'; import { useEffect, useState } from 'react'; -import { type FetcherWithComponents, Form, useFetcher } from 'react-router'; +import { Form } from 'react-router'; import Button from '~/components/Button'; import Input from '~/components/Input'; import TableList from '~/components/TableList'; @@ -37,18 +37,15 @@ export default function ManageDomains({ }, [searchDomains]); return ( -
+

Search Domains

Set custom DNS search domains for your Tailnet. When using Magic DNS, your tailnet domain is used as the first search domain.

{ - setActiveId(event.active.id); - }} + modifiers={[restrictToVerticalAxis, restrictToParentElement]} onDragEnd={(event) => { setActiveId(null); const { active, over } = event; @@ -70,6 +67,9 @@ export default function ManageDomains({ setLocalDomains(arrayMove(localDomains, oldIndex, newIndex)); } }} + onDragStart={(event) => { + setActiveId(event.active.id); + }} > {magic ? ( @@ -91,19 +91,19 @@ export default function ManageDomains({ > {localDomains.map((sd, index) => ( ))} {activeId ? ( ) : undefined} @@ -111,28 +111,28 @@ export default function ManageDomains({ {isDisabled ? undefined : (
- + @@ -164,11 +164,11 @@ function Domain({ domain, id, isDragging, isDisabled }: DomainProps) { return ( {isDragging ? undefined : ( - - + + diff --git a/app/routes/dns/components/manage-ns.tsx b/app/routes/dns/components/manage-ns.tsx index 285277f..ce57fd2 100644 --- a/app/routes/dns/components/manage-ns.tsx +++ b/app/routes/dns/components/manage-ns.tsx @@ -20,14 +20,14 @@ export default function ManageNS({ overrideLocalDns, }: Props) { return ( -
+

Nameservers

Set the nameservers used by devices on the Tailnet to resolve DNS queries.{' '} Learn more @@ -35,12 +35,12 @@ export default function ManageNS({

{Object.keys(nameservers).map((key) => ( ))} @@ -66,16 +66,17 @@ function NameserverList({ name, }: ListProps) { const list = isGlobal ? nameservers.global : nameservers[name]; + const submit = useSubmit(); + if (list.length === 0) { return null; } - const submit = useSubmit(); return (
{isGlobal ? ( -
+

Global Nameservers

@@ -87,8 +88,8 @@ function NameserverList({ names outside the tailnet. When disabled (default), devices will prefer their local DNS configuration. Learn More @@ -96,11 +97,10 @@ function NameserverList({

Override DNS servers

{ submit( { @@ -112,6 +112,7 @@ function NameserverList({ }, ); }} + switchClassName="h-[9px] w-[9px]" />
@@ -125,20 +126,20 @@ function NameserverList({

{ns}

- - + + diff --git a/app/routes/dns/components/manage-records.tsx b/app/routes/dns/components/manage-records.tsx index 75c84c4..7b915a7 100644 --- a/app/routes/dns/components/manage-records.tsx +++ b/app/routes/dns/components/manage-records.tsx @@ -13,14 +13,14 @@ interface Props { export default function ManageRecords({ records, isDisabled }: Props) { return ( -
+

DNS Records

Headscale supports adding custom DNS records to your Tailnet. As of now, only A and AAAA records are supported.{' '} Learn More @@ -32,7 +32,7 @@ export default function ManageRecords({ records, isDisabled }: Props) {

No DNS records found

) : ( - records.map((record, index) => ( + records.map((record) => (

{record.type}

-
-

{record.name}

-

{record.value}

+
+

{record.name}

+

+ {record.value} +

- - - + + + diff --git a/app/routes/dns/components/rename-tailnet.tsx b/app/routes/dns/components/rename-tailnet.tsx index 773e232..2849d99 100644 --- a/app/routes/dns/components/rename-tailnet.tsx +++ b/app/routes/dns/components/rename-tailnet.tsx @@ -9,21 +9,21 @@ interface Props { export default function RenameTailnet({ name, isDisabled }: Props) { return ( -
+

Tailnet Name

This is the base domain name of your Tailnet. Devices are accessible at{' '} [device].{name} when Magic DNS is enabled.

{ event.target.select(); }} + value={name} /> Rename Tailnet @@ -33,13 +33,13 @@ export default function RenameTailnet({ name, isDisabled }: Props) { Keep in mind that changing this can lead to all sorts of unexpected behavior and may break existing devices in your tailnet. - + diff --git a/app/routes/dns/overview.tsx b/app/routes/dns/overview.tsx index 5c4c42a..6648274 100644 --- a/app/routes/dns/overview.tsx +++ b/app/routes/dns/overview.tsx @@ -84,20 +84,20 @@ export default function Page() { tailnet. )} - + - + -
+

Magic DNS

Automatically register domain names for each device on the tailnet. @@ -108,7 +108,7 @@ export default function Page() { {' '} when Magic DNS is enabled.

- +
); diff --git a/app/routes/machines/overview.tsx b/app/routes/machines/overview.tsx index d8ffc64..d22a596 100644 --- a/app/routes/machines/overview.tsx +++ b/app/routes/machines/overview.tsx @@ -157,8 +157,8 @@ export default function Page({ loaderData }: Route.ComponentProps) { return ( <> -
-
+
+

Machines

Manage the devices connected to your Tailnet.{' '} @@ -210,85 +210,13 @@ export default function Page({ loaderData }: Route.ComponentProps) { : `${loaderData.populatedNodes.length} machines`}

- - - - - - {/* We only want to show the version column if there are agents */} - {loaderData.agent !== undefined ? ( +
+
- - -
- - {loaderData.magic ? ( - - - - Since MagicDNS is enabled, you can access devices based on - their name and also at{' '} - - [name]. - {loaderData.magic} - - - - ) : undefined} -
-
+ + - ) : undefined} - - - - - {filteredAndSortedNodes.length === 0 ? ( - - + ) : undefined} + - ) : ( - filteredAndSortedNodes.map((node) => ( - - )) - )} - -
- - Last Seen - {sortField === 'lastSeen' && - (sortDirection === 'asc' ? ( - - ) : ( - - ))} - -
+ + {loaderData.magic ? ( + + + + Since MagicDNS is enabled, you can access devices based + on their name and also at{' '} + + [name]. + {loaderData.magic} + + + + ) : undefined} + + + {/* We only want to show the version column if there are agents */} + {loaderData.agent !== undefined ? ( + + + - No machines found matching "{searchQuery}" - + +
+ + + {filteredAndSortedNodes.length === 0 ? ( + + + No machines found matching "{searchQuery}" + + + ) : ( + filteredAndSortedNodes.map((node) => ( + + )) + )} + + +
); } diff --git a/app/routes/settings/overview.tsx b/app/routes/settings/overview.tsx index c11a57a..b011efd 100644 --- a/app/routes/settings/overview.tsx +++ b/app/routes/settings/overview.tsx @@ -15,7 +15,7 @@ export default function Page({ }: Route.ComponentProps) { return (
-
+

Settings

The settings page is still under construction. As I'm able to add more @@ -23,7 +23,7 @@ export default function Page({ free to open an issue on the GitHub repository.

-
+

Pre-Auth Keys

Headscale fully supports pre-authentication keys in order to easily @@ -45,7 +45,7 @@ export default function Page({ {config && isOidcEnabled ? ( <> -

+

Authentication Restrictions

diff --git a/app/routes/settings/restrictions/overview.tsx b/app/routes/settings/restrictions/overview.tsx index 04a83c9..5dabccc 100644 --- a/app/routes/settings/restrictions/overview.tsx +++ b/app/routes/settings/restrictions/overview.tsx @@ -43,7 +43,7 @@ export default function Page({ return (
-
+

Settings diff --git a/app/routes/settings/restrictions/table.tsx b/app/routes/settings/restrictions/table.tsx index 51a6d98..321810a 100644 --- a/app/routes/settings/restrictions/table.tsx +++ b/app/routes/settings/restrictions/table.tsx @@ -19,7 +19,7 @@ export default function RestrictionTable({ isDisabled, }: RestrictionProps) { return ( -

+

Permitted {type.charAt(0).toUpperCase() + type.slice(1)}s

@@ -61,7 +61,7 @@ export default function RestrictionTable({ ) : ( {iconForType(type)} -

+

All {type}s are permitted to authenticate.

diff --git a/app/routes/users/overview.tsx b/app/routes/users/overview.tsx index 31f171f..a7057b6 100644 --- a/app/routes/users/overview.tsx +++ b/app/routes/users/overview.tsx @@ -114,32 +114,34 @@ export default function Page({ loaderData }: Route.ComponentProps) { Manage the users in your network and their permissions.

- - - - - - - - - - - {users - .sort((a, b) => a.name.localeCompare(b.name)) - .map((user) => ( - - ))} - -
UserRoleCreated AtLast Seen
+
+ + + + + + + + + + + {users + .sort((a, b) => a.name.localeCompare(b.name)) + .map((user) => ( + + ))} + +
UserRoleCreated AtLast Seen
+
); } diff --git a/app/tailwind.css b/app/tailwind.css index 8df054c..970eabd 100644 --- a/app/tailwind.css +++ b/app/tailwind.css @@ -65,6 +65,7 @@ @utility container { margin-inline: auto; padding-inline: 1rem; + max-width: 100%; /* biome-ignore lint/correctness/noUnknownFunction: Tailwind CSS */ @media (width >= theme(--breakpoint-sm)) {