enhancement(web): ui overhaul (#1155)

* Various WebUI changes and fixes.

* feat(tooltip): make tooltip display upwards

* fix(tooltip): place tooltip to the right

* fix(web): add missing ml-px to SwitchGroup header

current: https://i.imgur.com/2WXstPV.png
new: https://i.imgur.com/QGQ49mP.png

* fix(web): collapse sections

* fix(web):  improve freeleech section

* fix(web): rename action to action_components

Renamed the 'action' folder to 'action_components' to resolve import issues due to case sensitivity.

* fix(web): align CollapsibleSection

Old Advanced tab: https://i.imgur.com/MXaJ5eJ.png
New Advanced tab: https://i.imgur.com/4nPJJRw.png
Music tab for comparison: https://i.imgur.com/I59X7ot.png

* fix(web): remove invalid CSS class

* revert: vertical padding on switchgroup

added py-0 on the freeleech part instead

* feat(settings): add back log files

* fix(settings): irc channels and font sizes

* fix(components): radio select roundness

* fix(styling): various minor changes

* fix(filters): remove jitter fields

---------

Co-authored-by: ze0s <43699394+zze0s@users.noreply.github.com>
Co-authored-by: soup <soup@r4tio.dev>
Co-authored-by: ze0s <ze0s@riseup.net>
This commit is contained in:
stacksmash76 2023-11-18 13:46:16 +00:00 committed by GitHub
parent a274d9ddce
commit e842a7bd42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 4378 additions and 4361 deletions

View file

@ -10,56 +10,67 @@ import type { FieldProps } from "formik";
import type { FieldArrayRenderProps } from "formik";
import { Field, FieldArray, FormikErrors, FormikValues } from "formik";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
import Select from "react-select";
import { Dialog } from "@headlessui/react";
import { IrcAuthMechanismTypeOptions, OptionBasicTyped } from "@domain/constants";
import { ircKeys } from "@screens/settings/Irc";
import { APIClient } from "@api/APIClient";
import { NumberFieldWide, PasswordFieldWide, SwitchGroupWide, SwitchGroupWideRed, TextFieldWide } from "@components/inputs";
import { NumberFieldWide, PasswordFieldWide, SwitchGroupWide, TextFieldWide } from "@components/inputs";
import { SlideOver } from "@components/panels";
import Toast from "@components/notifications/Toast";
import * as common from "@components/inputs/common";
import { classNames } from "@utils";
interface ChannelsFieldArrayProps {
channels: IrcChannel[];
}
const ChannelsFieldArray = ({ channels }: ChannelsFieldArrayProps) => (
<div className="p-6">
<div className="px-4">
<FieldArray name="channels">
{({ remove, push }: FieldArrayRenderProps) => (
<div className="flex flex-col space-y-2 border-2 border-dashed dark:border-gray-700 p-4">
<div className="flex flex-col space-y-2">
{channels && channels.length > 0 ? (
channels.map((_channel: IrcChannel, index: number) => {
const isDisabled = channels[index].name === "#ptp-announce-dev";
channels.map((channel: IrcChannel, index) => {
const isDisabled = channel.name === "#ptp-announce-dev";
return (
<div key={index} className="flex justify-between">
<div className="flex">
<div key={index} className="flex justify-between border dark:border-gray-700 dark:bg-gray-815 p-2 rounded-md">
<div className="flex gap-2">
<Field name={`channels.${index}.name`}>
{({ field }: FieldProps) => (
{({ field, meta }: FieldProps) => (
<input
{...field}
type="text"
value={field.value ?? ""}
onChange={field.onChange}
placeholder="#Channel"
className={`mr-4 focus:ring-blue-500 dark:focus:ring-blue-500 focus:border-blue-500 dark:focus:border-blue-500 border-gray-300 dark:border-gray-600 block w-full shadow-sm sm:text-sm rounded-md
${isDisabled ? "disabled dark:bg-gray-800 dark:text-gray-500" : "dark:bg-gray-700 dark:text-white"}`}
className={classNames(
meta.touched && meta.error
? "border-red-500 focus:ring-red-500 focus:border-red-500"
: "border-gray-300 dark:border-gray-700 focus:ring-blue-500 dark:focus:ring-blue-500 focus:border-blue-500 dark:focus:border-blue-500",
"block w-full shadow-sm sm:text-sm rounded-md border py-2.5",
isDisabled ? "disabled dark:bg-gray-700 dark:text-gray-400 cursor-not-allowed" : "bg-gray-100 dark:bg-gray-850 dark:text-gray-100"
)}
disabled={isDisabled}
/>
)}
</Field>
<Field name={`channels.${index}.password`}>
{({ field }: FieldProps) => (
{({ field, meta }: FieldProps) => (
<input
{...field}
type="text"
value={field.value ?? ""}
onChange={field.onChange}
placeholder="Password"
className={`mr-4 focus:ring-blue-500 dark:focus:ring-blue-500 focus:border-blue-500 dark:focus:border-blue-500 border-gray-300 dark:border-gray-600 block w-full shadow-sm sm:text-sm rounded-md
${isDisabled ? "disabled dark:bg-gray-800 dark:text-gray-500" : "dark:bg-gray-700 dark:text-white"}`}
placeholder="Channel password"
className={classNames(
meta.touched && meta.error
? "border-red-500 focus:ring-red-500 focus:border-red-500"
: "border-gray-300 dark:border-gray-700 focus:ring-blue-500 dark:focus:ring-blue-500 focus:border-blue-500 dark:focus:border-blue-500",
"block w-full shadow-sm sm:text-sm rounded-md border py-2.5",
isDisabled ? "disabled dark:bg-gray-700 dark:text-white cursor-not-allowed" : "bg-gray-100 dark:bg-gray-850 dark:text-gray-100"
)}
disabled={isDisabled}
/>
)}
@ -68,8 +79,10 @@ const ChannelsFieldArray = ({ channels }: ChannelsFieldArrayProps) => (
<button
type="button"
className={`bg-white dark:bg-gray-700 rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-500
${isDisabled ? "disabled hidden" : ""}`}
className={classNames(
"bg-white dark:bg-gray-700 rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-500",
isDisabled ? "hidden" : ""
)}
onClick={() => remove(index)}
disabled={isDisabled}
>
@ -204,7 +217,16 @@ export function IrcNetworkAddForm({ isOpen, toggle }: AddFormProps) {
/>
<PasswordFieldWide name="invite_command" label="Invite command" />
<ChannelsFieldArray channels={values.channels} />
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
<div className="px-4 space-y-1 mb-8">
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Channels</Dialog.Title>
<p className="text-sm text-gray-500 dark:text-gray-400">
Channels to join.
</p>
</div>
<ChannelsFieldArray channels={values.channels} />
</div>
</div>
)}
</SlideOver>
@ -324,7 +346,7 @@ export function IrcNetworkUpdateForm({
required={true}
/>
<SwitchGroupWideRed name="enabled" label="Enabled" />
<SwitchGroupWide name="enabled" label="Enabled" />
<TextFieldWide
name="server"
label="Server"
@ -388,12 +410,20 @@ export function IrcNetworkUpdateForm({
label="Password"
help="NickServ / SASL password."
/>
</div>
<PasswordFieldWide name="invite_command" label="Invite command" />
<ChannelsFieldArray channels={values.channels} />
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
<div className="px-4 space-y-1 mb-8">
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Channels</Dialog.Title>
<p className="text-sm text-gray-500 dark:text-gray-400">
Channels are added when you setup IRC indexers. Do not edit unless you know what you are doing.
</p>
</div>
<ChannelsFieldArray channels={values.channels} />
</div>
</div>
)}
</SlideOver>
@ -429,10 +459,12 @@ function SelectField<T>({ name, label, options }: SelectFieldProps<T>) {
isClearable={true}
isSearchable={true}
components={{
Input,
Control,
Menu,
Option
Input: common.SelectInput,
Control: common.SelectControl,
Menu: common.SelectMenu,
Option: common.SelectOption,
IndicatorSeparator: common.IndicatorSeparator,
DropdownIndicator: common.DropdownIndicator
}}
placeholder="Choose a type"
styles={{
@ -468,44 +500,3 @@ function SelectField<T>({ name, label, options }: SelectFieldProps<T>) {
</div>
);
}
const Input = (props: InputProps) => {
return (
<components.Input
{...props}
inputClassName="outline-none border-none shadow-none focus:ring-transparent"
className="text-gray-400 dark:text-gray-100"
children={props.children}
/>
);
};
const Control = (props: ControlProps) => {
return (
<components.Control
{...props}
className="p-1 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
children={props.children}
/>
);
};
const Menu = (props: MenuProps) => {
return (
<components.Menu
{...props}
className="dark:bg-gray-800 border border-gray-300 dark:border-gray-700 dark:text-gray-400 rounded-md shadow-sm"
children={props.children}
/>
);
};
const Option = (props: OptionProps) => {
return (
<components.Option
{...props}
className="dark:text-gray-400 dark:bg-gray-800 dark:hover:bg-gray-900 dark:focus:bg-gray-900"
children={props.children}
/>
);
};