feat: unify all colors

This commit is contained in:
Aarnav Tale 2025-02-04 17:21:03 -05:00
parent d1f6c450c0
commit 287ac2dff0
No known key found for this signature in database
30 changed files with 233 additions and 284 deletions

View file

@ -90,7 +90,7 @@ export default function MachineRow({
return (
<tr
key={machine.id}
className="hover:bg-zinc-100 dark:hover:bg-zinc-800 group"
className="group hover:bg-headplane-50 dark:hover:bg-headplane-950"
>
<td className="pl-0.5 py-2">
<Link to={`/machines/${machine.id}`} className="group/link h-full">
@ -103,9 +103,7 @@ export default function MachineRow({
>
{machine.givenName}
</p>
<p className="text-sm text-gray-500 dark:text-gray-300 font-mono">
{machine.name}
</p>
<p className="text-sm font-mono opacity-50">{machine.name}</p>
<div className="flex gap-1 mt-1">
{tags.map((tag) => (
<Chip key={tag} text={tag} />
@ -152,12 +150,12 @@ export default function MachineRow({
<p className="leading-snug">
{hinfo.getTSVersion(stats)}
</p>
<p className="text-sm text-gray-500 dark:text-gray-300 max-w-48 truncate">
<p className="text-sm opacity-50 max-w-48 truncate">
{hinfo.getOSInfo(stats)}
</p>
</>
) : (
<p className="text-sm text-gray-500 dark:text-gray-300">
<p className="text-sm opacity-50">
Unknown
</p>
)}
@ -167,7 +165,7 @@ export default function MachineRow({
<span
className={cn(
'flex items-center gap-x-1 text-sm',
'text-gray-500 dark:text-gray-400',
'text-headplane-600 dark:text-headplane-300',
)}
>
<StatusCircle

View file

@ -23,7 +23,7 @@ export default function Rename({
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
<Dialog.Panel>
<Dialog.Title>Edit machine name for {machine.givenName}</Dialog.Title>
<Dialog.Text>
<Dialog.Text className="mb-6">
This name is shown in the admin panel, in Tailscale clients, and used
when generating MagicDNS names.
</Dialog.Text>
@ -38,7 +38,7 @@ export default function Rename({
/>
{magic ? (
name.length > 0 && name !== machine.givenName ? (
<p className="text-sm text-gray-500 dark:text-gray-300 leading-tight">
<p className="text-sm text-headplane-600 dark:text-headplane-300 leading-tight mt-2">
This machine will be accessible by the hostname{' '}
<Code className="text-sm">
{name.toLowerCase().replaceAll(/\s+/g, '-')}
@ -48,7 +48,7 @@ export default function Rename({
will no longer point to this machine.
</p>
) : (
<p className="text-sm text-gray-500 dark:text-gray-300 leading-tight">
<p className="text-sm text-headplane-600 dark:text-headplane-300 leading-tight mt-2">
This machine is accessible by the hostname{' '}
<Code className="text-sm">{machine.givenName}</Code>.
</p>

View file

@ -1,8 +1,10 @@
import { GlobeLock, RouteOff } from 'lucide-react';
import { useMemo } from 'react';
import { useFetcher } from 'react-router';
import Dialog from '~/components/Dialog';
import Link from '~/components/Link';
import Switch from '~/components/Switch';
import TableList from '~/components/TableList';
import type { Machine, Route } from '~/types';
import cn from '~/utils/cn';
@ -59,32 +61,17 @@ export default function Routes({
Learn More
</Link>
</Dialog.Text>
<div
className={cn(
'rounded-lg overflow-y-auto my-2',
'divide-y divide-zinc-200 dark:divide-zinc-700 align-top',
'border border-zinc-200 dark:border-zinc-700',
)}
>
<TableList className="mt-4">
{subnet.length === 0 ? (
<div
className={cn(
'flex py-4 px-4 bg-ui-100 dark:bg-ui-800',
'items-center justify-center',
'text-ui-600 dark:text-ui-300',
)}
>
<p>No routes are advertised on this machine.</p>
</div>
<TableList.Item className="flex flex-col items-center gap-2.5 py-4 opacity-70">
<RouteOff />
<p className="font-semibold">
No routes are advertised by this machine
</p>
</TableList.Item>
) : undefined}
{subnet.map((route) => (
<div
key={route.id}
className={cn(
'flex py-2 px-4 bg-ui-100 dark:bg-ui-800',
'items-center justify-between',
)}
>
<TableList.Item key={route.id}>
<p>{route.prefix}</p>
<Switch
defaultSelected={route.enabled}
@ -101,9 +88,9 @@ export default function Routes({
});
}}
/>
</div>
</TableList.Item>
))}
</div>
</TableList>
<Dialog.Text className="font-bold mt-8">Exit nodes</Dialog.Text>
<Dialog.Text>
Allow your network to route internet traffic through this machine.{' '}
@ -114,30 +101,14 @@ export default function Routes({
Learn More
</Link>
</Dialog.Text>
<div
className={cn(
'rounded-lg overflow-y-auto my-2',
'divide-y divide-zinc-200 dark:divide-zinc-700 align-top',
'border border-zinc-200 dark:border-zinc-700',
)}
>
<TableList className="mt-4">
{exit.length === 0 ? (
<div
className={cn(
'flex py-4 px-4 bg-ui-100 dark:bg-ui-800',
'items-center justify-center',
'text-ui-600 dark:text-ui-300',
)}
>
<p>This machine is not an exit node.</p>
</div>
<TableList.Item className="flex flex-col items-center gap-2.5 py-4 opacity-70">
<GlobeLock />
<p className="font-semibold">This machine is not an exit node</p>
</TableList.Item>
) : (
<div
className={cn(
'flex py-2 px-4 bg-ui-100 dark:bg-ui-800',
'items-center justify-between',
)}
>
<TableList.Item>
<p>Use as exit node</p>
<Switch
defaultSelected={exitEnabled}
@ -154,9 +125,9 @@ export default function Routes({
});
}}
/>
</div>
</TableList.Item>
)}
</div>
</TableList>
</Dialog.Panel>
</Dialog>
);

View file

@ -1,4 +1,4 @@
import { Plus, X } from 'lucide-react';
import { Plus, TagsIcon, X } from 'lucide-react';
import { useState } from 'react';
import Button from '~/components/Button';
import Dialog from '~/components/Dialog';
@ -38,15 +38,10 @@ export default function Tags({ machine, isOpen, setIsOpen }: TagsProps) {
<input type="hidden" name="tags" value={tags.join(',')} />
<TableList className="mt-4">
{tags.length === 0 ? (
<div
className={cn(
'flex py-4 px-4 bg-ui-100 dark:bg-ui-800',
'items-center justify-center rounded-t-lg',
'text-ui-600 dark:text-ui-300',
)}
>
<p>No tags are set on this machine.</p>
</div>
<TableList.Item className="flex flex-col items-center gap-2.5 py-4 opacity-70">
<TagsIcon />
<p className="font-semibold">No tags are set on this machine</p>
</TableList.Item>
) : (
tags.map((item) => (
<TableList.Item className="font-mono" key={item} id={item}>

View file

@ -1,20 +1,12 @@
import {
CheckCircleIcon,
GearIcon,
InfoIcon,
PersonIcon,
SkipIcon,
} from '@primer/octicons-react';
import { CheckCircle, CircleSlash, Info, UserCircle } from 'lucide-react';
import { useMemo, useState } from 'react';
import type { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router';
import { Link as RemixLink, useLoaderData } from 'react-router';
import Attribute from '~/components/Attribute';
import Button from '~/components/Button';
import Card from '~/components/Card';
import Chip from '~/components/Chip';
import Link from '~/components/Link';
import Menu from '~/components/Menu';
import StatusCircle from '~/components/StatusCircle';
import Tooltip from '~/components/Tooltip';
import type { Machine, Route, User } from '~/types';
@ -23,7 +15,6 @@ import { loadContext } from '~/utils/config/headplane';
import { loadConfig } from '~/utils/config/headscale';
import { pull } from '~/utils/headscale';
import { getSession } from '~/utils/sessions.server';
import { menuAction } from './action';
import MenuOptions from './components/menu';
import Routes from './dialogs/routes';
@ -126,11 +117,11 @@ export default function Page() {
</p>
<div
className={cn(
'flex justify-between items-center',
'border-b border-ui-100 dark:border-ui-800',
'flex justify-between items-center pb-2',
'border-b border-headplane-100 dark:border-headplane-800',
)}
>
<span className="flex items-baseline gap-x-4 text-sm mb-4">
<span className="flex items-baseline gap-x-4 text-sm">
<h1 className="text-2xl font-medium">{machine.givenName}</h1>
<StatusCircle isOnline={machine.online} className="w-4 h-4" />
</span>
@ -144,30 +135,25 @@ export default function Page() {
/>
</div>
<div className="flex gap-1 mb-4">
<div className="border-r border-ui-100 dark:border-ui-800 p-2 pr-4">
<span className="text-sm text-ui-600 dark:text-ui-300 flex items-center gap-x-1">
<div className="border-r border-headplane-100 dark:border-headplane-800 p-2 pr-4">
<span className="text-sm text-headplane-600 dark:text-headplane-300 flex items-center gap-x-1">
Managed by
<Tooltip>
<InfoIcon className="w-3.5 h-3.5" />
<Info className="p-1" />
<Tooltip.Body>
By default, a machines permissions match its creators.
</Tooltip.Body>
</Tooltip>
</span>
<div className="flex items-center gap-x-2.5 mt-1">
<div
className={cn(
'rounded-full h-7 w-7 flex items-center justify-center',
'border border-ui-200 dark:border-ui-700',
)}
>
<PersonIcon className="w-4 h-4" />
</div>
<UserCircle />
{machine.user.name}
</div>
</div>
<div className="p-2 pl-4">
<p className="text-sm text-ui-600 dark:text-ui-300">Status</p>
<p className="text-sm text-headplane-600 dark:text-headplane-300">
Status
</p>
<div className="flex gap-1 mt-1 mb-8">
{tags.map((tag) => (
<Chip key={tag} text={tag} />
@ -202,10 +188,10 @@ export default function Page() {
)}
>
<div>
<span className="text-ui-600 dark:text-ui-300 flex items-center gap-x-1">
<span className="text-headplane-600 dark:text-headplane-300 flex items-center gap-x-1">
Approved
<Tooltip>
<InfoIcon className="w-3.5 h-3.5" />
<Info className="w-3.5 h-3.5" />
<Tooltip.Body>
Traffic to these routes are being routed through this machine.
</Tooltip.Body>
@ -213,7 +199,7 @@ export default function Page() {
</span>
<div className="mt-1">
{subnetApproved.length === 0 ? (
<span className="text-ui-400 dark:text-ui-300"></span>
<span className="opacity-50"></span>
) : (
<ul className="leading-normal">
{subnetApproved.map((route) => (
@ -233,10 +219,10 @@ export default function Page() {
</Button>
</div>
<div>
<span className="text-ui-600 dark:text-ui-300 flex items-center gap-x-1">
<span className="text-headplane-600 dark:text-headplane-300 flex items-center gap-x-1">
Awaiting Approval
<Tooltip>
<InfoIcon className="w-3.5 h-3.5" />
<Info className="w-3.5 h-3.5" />
<Tooltip.Body>
This machine is advertising these routes, but they must be
approved before traffic will be routed to them.
@ -245,7 +231,7 @@ export default function Page() {
</span>
<div className="mt-1">
{subnet.length === 0 ? (
<span className="text-ui-400 dark:text-ui-300"></span>
<span className="opacity-50"></span>
) : (
<ul className="leading-normal">
{subnet.map((route) => (
@ -265,10 +251,10 @@ export default function Page() {
</Button>
</div>
<div>
<span className="text-ui-600 dark:text-ui-300 flex items-center gap-x-1">
<span className="text-headplane-600 dark:text-headplane-300 flex items-center gap-x-1">
Exit Node
<Tooltip>
<InfoIcon className="w-3.5 h-3.5" />
<Info className="w-3.5 h-3.5" />
<Tooltip.Body>
Whether this machine can act as an exit node for your tailnet.
</Tooltip.Body>
@ -276,15 +262,15 @@ export default function Page() {
</span>
<div className="mt-1">
{exit.length === 0 ? (
<span className="text-ui-400 dark:text-ui-300"></span>
<span className="opacity-50"></span>
) : exitEnabled ? (
<span className="flex items-center gap-x-1">
<CheckCircleIcon className="w-3.5 h-3.5 text-green-700" />
<CheckCircle className="w-3.5 h-3.5 text-green-700" />
Allowed
</span>
) : (
<span className="flex items-center gap-x-1">
<SkipIcon className="w-3.5 h-3.5 text-red-700" />
<CircleSlash className="w-3.5 h-3.5 text-red-700" />
Awaiting Approval
</span>
)}

View file

@ -59,10 +59,10 @@ export default function Page() {
return (
<>
<div className="flex justify-between items-center mb-8">
<div className="flex justify-between items-center mb-6">
<div className="flex flex-col w-2/3">
<h1 className="text-2xl font-medium mb-4">Machines</h1>
<p className="text-gray-700 dark:text-gray-300">
<h1 className="text-2xl font-medium mb-2">Machines</h1>
<p>
Manage the devices connected to your Tailnet.{' '}
<Link
to="https://tailscale.com/kb/1372/manage-devices"
@ -78,9 +78,9 @@ export default function Page() {
/>
</div>
<table className="table-auto w-full rounded-lg">
<thead className="text-gray-500 dark:text-gray-400">
<thead className="text-headplane-600 dark:text-headplane-300">
<tr className="text-left px-0.5">
<th className="pb-2">Name</th>
<th className="uppercase text-xs font-bold pb-2">Name</th>
<th className="pb-2 w-1/4">
<div className="flex items-center gap-x-1">
<p className="uppercase text-xs font-bold">Addresses</p>
@ -99,14 +99,14 @@ export default function Page() {
) : undefined}
</div>
</th>
{/**<th className="pb-2">Version</th>**/}
<th className="pb-2">Last Seen</th>
{/**<th className="uppercase text-xs font-bold pb-2">Version</th>**/}
<th className="uppercase text-xs font-bold pb-2">Last Seen</th>
</tr>
</thead>
<tbody
className={cn(
'divide-y divide-zinc-200 dark:divide-zinc-700 align-top',
'border-t border-zinc-200 dark:border-zinc-700',
'divide-y divide-headplane-100 dark:divide-headplane-800 align-top',
'border-t border-headplane-100 dark:border-headplane-800',
)}
>
{data.nodes.map((machine) => (