feat(web): mobile UI improvements (#359)

* enhancement: improved alerts component contrast
enhancement: simplified and improved radio switch group look
fix: fixed inconsistent spacing in input components (there's still some work left to be done)
fix: made slideover panel display on full width on mobile devices
enhancement: made forms more accessible to mobile users, adapter changes in accordance with the previous input components fix
fix: fixed misspelling in NotificationForms filename
chore: cleaned up code
fix: made filter table top edges less round and improved look
fix: fixed a bug where when a modal/slideover component was opened, a 1px white bar would be shown in one of the modal parent elements (for the fix see L89 in screens/settings/DwonloadClient.tsx)
enhancement: improved responsiveness for irc network list

* Fixed 2 small comma warnings from ESLint

Co-authored-by: anonymous <anonymous>
This commit is contained in:
stacksmash76 2022-07-17 23:34:49 +02:00 committed by GitHub
parent f961115dac
commit 3da594ec75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 758 additions and 640 deletions

View file

@ -1,41 +1,35 @@
import { useQuery } from "react-query";
import {
simplifyDate,
IsEmptyDate
} from "../../utils";
import {
IrcNetworkAddForm,
IrcNetworkUpdateForm
} from "../../forms";
import { simplifyDate, IsEmptyDate, classNames } from "../../utils";
import { IrcNetworkAddForm, IrcNetworkUpdateForm } from "../../forms";
import { useToggle } from "../../hooks/hooks";
import { APIClient } from "../../api/APIClient";
import { EmptySimple } from "../../components/emptystates";
import {ExclamationCircleIcon} from "@heroicons/react/outline";
import { ExclamationCircleIcon } from "@heroicons/react/outline";
import { LockClosedIcon, LockOpenIcon } from "@heroicons/react/solid";
export const IrcSettings = () => {
const [addNetworkIsOpen, toggleAddNetwork] = useToggle(false);
const { data } = useQuery(
"networks",
() => APIClient.irc.getNetworks(),
{
refetchOnWindowFocus: false,
// Refetch every 3 seconds
refetchInterval: 3000
}
);
const { data } = useQuery("networks", () => APIClient.irc.getNetworks(), {
refetchOnWindowFocus: false,
// Refetch every 3 seconds
refetchInterval: 3000
});
return (
<div className="divide-y divide-gray-200 lg:col-span-9">
<div className="lg:col-span-9">
<IrcNetworkAddForm isOpen={addNetworkIsOpen} toggle={toggleAddNetwork} />
<div className="py-6 px-4 sm:p-6 lg:pb-8">
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
<div className="ml-4 mt-4">
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">IRC</h3>
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">
IRC
</h3>
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
IRC networks and channels. Click on a network to view channel status.
IRC networks and channels. Click on a network to view channel
status.
</p>
</div>
<div className="ml-4 mt-4 flex-shrink-0">
@ -44,35 +38,46 @@ export const IrcSettings = () => {
onClick={toggleAddNetwork}
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Add new
Add new
</button>
</div>
</div>
{data && data.length > 0 ? (
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
<ol className="min-w-full">
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
{/* <div className="col-span-1 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Enabled</div> */}
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Network</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Server</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Nick</div>
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Network
</div>
<div className="col-span-5 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Server
</div>
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Nick
</div>
</li>
{data && data.map((network, idx) => (
<ListItem key={idx} idx={idx} network={network} />
))}
{data &&
data.map((network, idx) => (
<ListItem key={idx} idx={idx} network={network} />
))}
</ol>
</section>
) : <EmptySimple title="No networks" subtitle="Add a new network" buttonText="New network" buttonAction={toggleAddNetwork} />}
) : (
<EmptySimple
title="No networks"
subtitle="Add a new network"
buttonText="New network"
buttonAction={toggleAddNetwork}
/>
)}
</div>
</div>
);
};
interface ListItemProps {
idx: number;
network: IrcNetworkWithHealth;
idx: number;
network: IrcNetworkWithHealth;
}
const ListItem = ({ idx, network }: ListItemProps) => {
@ -80,33 +85,91 @@ const ListItem = ({ idx, network }: ListItemProps) => {
const [edit, toggleEdit] = useToggle(false);
return (
<li key={idx}>
<div className="grid grid-cols-12 gap-2 lg:gap-4 items-center hover:bg-gray-50 dark:hover:bg-gray-700 py-4">
<IrcNetworkUpdateForm
isOpen={updateIsOpen}
toggle={toggleUpdate}
network={network}
/>
<li key={idx} >
<div className="grid grid-cols-12 gap-4 items-center hover:bg-gray-50 dark:hover:bg-gray-700 py-4">
<IrcNetworkUpdateForm isOpen={updateIsOpen} toggle={toggleUpdate} network={network} />
<div className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer" onClick={toggleEdit}>
<span className="relative inline-flex items-center">
{
network.enabled ? (
networkHealthy(network) ? (
<span className="mr-3 flex h-3 w-3 relative" title={`Connected since: ${simplifyDate(network.connected_since)}`}>
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75"/>
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500"/>
<div
className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer"
onClick={toggleEdit}
>
<div className="flex">
<span className="relative inline-flex items-center ml-1">
{network.enabled ? (
IsNetworkHealthy(network) ? (
<span
className="mr-3 flex h-3 w-3 relative"
title={`Connected since: ${simplifyDate(network.connected_since)}`}
>
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
</span>
) : <span className="mr-3 flex items-center" title={network.connection_errors.toString()}><ExclamationCircleIcon className="h-4 w-4 text-red-400 hover:text-red-600" /></span>
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
}
{network.name}
</span>
) : (
<span
className="mr-3 flex items-center"
title={network.connection_errors.toString()}
>
<ExclamationCircleIcon className="h-4 w-4 text-red-400 hover:text-red-600" />
</span>
)
) : (
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
)}
</span>
<div className="overflow-x-auto flex">
{network.name}
</div>
</div>
</div>
<div
className="col-span-5 sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
onClick={toggleEdit}
>
<div
className="overflow-x-auto flex items-center"
title={network.tls ? "Secured using TLS" : "Insecure, not using TLS"}
>
<div className="min-h-2 min-w-2">
{network.tls ? (
<LockClosedIcon
className={classNames(
"mr-2 h-4 w-4",
network.enabled ? "text-green-600" : "text-gray-500"
)}
/>
) : (
<LockOpenIcon className={classNames(
"mr-2 h-4 w-4",
network.enabled ? "text-red-500" : "text-yellow-500"
)} />
)}
</div>
<p className="break-all">
{network.server}:{network.port}
</p>
</div>
</div>
<div className="col-span-4 flex justify-between items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.server}:{network.port} {network.tls && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-300 text-green-800 dark:text-green-900">TLS</span>}</div>
{network.nickserv && network.nickserv.account ? (
<div className="col-span-4 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.nickserv.account}</div>
) : <div className="col-span-4" />}
<div
className="col-span-3 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
onClick={toggleEdit}
>
<div className="overflow-x-auto flex">
{network.nickserv.account}
</div>
</div>
) : (
<div className="col-span-3" />
)}
<div className="col-span-1 text-sm text-gray-500 dark:text-gray-400">
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdate}>
<span
className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer"
onClick={toggleUpdate}
>
Edit
</span>
</div>
@ -117,39 +180,58 @@ const ListItem = ({ idx, network }: ListItemProps) => {
{network.channels.length > 0 ? (
<ol>
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Channel</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Monitoring since</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Last announce</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Channel
</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Monitoring since
</div>
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Last announce
</div>
</li>
{network.channels.map(c => (
{network.channels.map((c) => (
<li key={c.id} className="text-gray-500 dark:text-gray-400">
<div className="grid grid-cols-12 gap-4 items-center py-4">
<div className="col-span-4 flex items-center sm:px-6 ">
<span className="relative inline-flex items-center">
{
network.enabled ? (
c.monitoring ? (
<span className="mr-3 flex h-3 w-3 relative" title="monitoring">
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75"/>
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500"/>
</span>
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
}
{network.enabled ? (
c.monitoring ? (
<span
className="mr-3 flex h-3 w-3 relative"
title="monitoring"
>
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
</span>
) : (
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />
)
) : (
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
)}
{c.name}
</span>
</div>
<div className="col-span-4 flex items-center sm:px-6 ">
<span className="" title={simplifyDate(c.monitoring_since)}>{IsEmptyDate(c.monitoring_since)}</span>
<span title={simplifyDate(c.monitoring_since)}>
{IsEmptyDate(c.monitoring_since)}
</span>
</div>
<div className="col-span-4 flex items-center sm:px-6 ">
<span className="" title={simplifyDate(c.last_announce)}>{IsEmptyDate(c.last_announce)}</span>
<span title={simplifyDate(c.last_announce)}>
{IsEmptyDate(c.last_announce)}
</span>
</div>
</div>
</li>
))}
</ol>
) : <div className="flex text-center justify-center py-4 dark:text-gray-500"><p>No channels!</p></div>}
) : (
<div className="flex text-center justify-center py-4 dark:text-gray-500">
<p>No channels!</p>
</div>
)}
</div>
</div>
)}
@ -157,10 +239,5 @@ const ListItem = ({ idx, network }: ListItemProps) => {
);
};
function networkHealthy(network: IrcNetworkWithHealth): boolean {
if (network.connection_errors.length > 0) {
return false
}
return true
}
const IsNetworkHealthy = (network: IrcNetworkWithHealth) =>
network.connection_errors.length <= 0;