Rewrite all styles to tailwind CSS from Bootstrap by @arccik (#58)
* add tailwindcss * add header component with logo and add torrent buttons * remove bootstrap from few files replace it with tailwindcss classes, add card which diplay all nessesarry information about torrent and current state * Add modal component and reorganize components folder * add useModal hook to render modal though react portal, remove UrlPromptModal and replace it with useModal. * add taliwindcss to Desctop app * removed bootstrap from deleteTorrentModal replace it with useModal * replacing bootstrap with useModal * saving * Saving * Header and cards now look good * Modals still broken... * still doesnt work * Finally it scrolls * Continuing to fix bugs * Continuing to fix bugs * Aler * Getting better * Desktop doesnt work with tailwind somehow * Desktop now works with tailwind * Styles fully work * (De)select all buttons * fix alert styles * Animate progress bar * Progress bar + error colors * Fix error message * Torrent status icon (#56) * add statusIcon component to display icon of the torrent status * change props name and remove isDownloading variable * Tweak styles for icon * Tweak styles * Update styles --------- Co-authored-by: Artur Lozovski <arccik@gmail.com>
This commit is contained in:
parent
911bf3a0d5
commit
50fc7f2f01
62 changed files with 7454 additions and 1776 deletions
|
|
@ -1,9 +1,15 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { ReactNode, useState } from "react";
|
||||
import { RqbitDesktopConfig } from "./configuration";
|
||||
import { Button, Form, Modal, Row, Tab, Tabs } from "react-bootstrap";
|
||||
import { ErrorComponent } from "rqbit-webui/src/components/ErrorComponent";
|
||||
import { invokeAPI } from "./api";
|
||||
import { ErrorDetails } from "rqbit-webui/src/api-types";
|
||||
import { FormCheckbox } from "rqbit-webui/src/components/forms/FormCheckbox";
|
||||
import { FormInput as FI } from "rqbit-webui/src/components/forms/FormInput";
|
||||
import { ModalBody } from "rqbit-webui/src/components/modal/ModalBody";
|
||||
import { Modal } from "rqbit-webui/src/components/modal/Modal";
|
||||
import { Fieldset } from "rqbit-webui/src/components/forms/Fieldset";
|
||||
import { ModalFooter } from "rqbit-webui/src/components/modal/ModalFooter";
|
||||
import { Button } from "rqbit-webui/src/components/buttons/Button";
|
||||
|
||||
const FormCheck: React.FC<{
|
||||
label: string;
|
||||
|
|
@ -14,19 +20,14 @@ const FormCheck: React.FC<{
|
|||
help?: string;
|
||||
}> = ({ label, name, checked, onChange, disabled, help }) => {
|
||||
return (
|
||||
<Form.Group as={Row} controlId={name} className="mb-3">
|
||||
<Form.Label className="col-4">{label}</Form.Label>
|
||||
<div className="col-8">
|
||||
<Form.Check
|
||||
type="switch"
|
||||
name={name}
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
{help && <div className="form-text">{help}</div>}
|
||||
</Form.Group>
|
||||
<FormCheckbox
|
||||
label={label}
|
||||
name={name}
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
help={help}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -40,22 +41,47 @@ const FormInput: React.FC<{
|
|||
help?: string;
|
||||
}> = ({ label, name, value, inputType, onChange, disabled, help }) => {
|
||||
return (
|
||||
<Form.Group as={Row} controlId={name} className="mb-3">
|
||||
<Form.Label className="col-4 col-form-label">{label}</Form.Label>
|
||||
<div className="col-8">
|
||||
<Form.Control
|
||||
type={inputType}
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
{help && <div className="form-text">{help}</div>}
|
||||
</Form.Group>
|
||||
<FI
|
||||
inputType={inputType}
|
||||
name={name}
|
||||
value={value as string}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
label={label}
|
||||
help={help}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type TAB =
|
||||
| "Home"
|
||||
| "DHT"
|
||||
| "Session"
|
||||
| "Peer options"
|
||||
| "HTTP API"
|
||||
| "TCP Listen";
|
||||
|
||||
const TABS: readonly TAB[] = [
|
||||
"Home",
|
||||
"DHT",
|
||||
"Session",
|
||||
"TCP Listen",
|
||||
"Peer options",
|
||||
"HTTP API",
|
||||
] as const;
|
||||
|
||||
const Tab: React.FC<{
|
||||
name: TAB;
|
||||
currentTab: TAB;
|
||||
children: ReactNode;
|
||||
}> = ({ name, currentTab, children }) => {
|
||||
const show = name === currentTab;
|
||||
if (!show) {
|
||||
return;
|
||||
}
|
||||
return <div>{children}</div>;
|
||||
};
|
||||
|
||||
export const ConfigModal: React.FC<{
|
||||
show: boolean;
|
||||
handleStartReconfigure: () => void;
|
||||
|
|
@ -74,6 +100,8 @@ export const ConfigModal: React.FC<{
|
|||
let [config, setConfig] = useState<RqbitDesktopConfig>(initialConfig);
|
||||
let [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
let [tab, setTab] = useState<TAB>("Home");
|
||||
|
||||
const [error, setError] = useState<any | null>(null);
|
||||
|
||||
const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
|
|
@ -143,27 +171,46 @@ export const ConfigModal: React.FC<{
|
|||
};
|
||||
|
||||
return (
|
||||
<Modal show={show} size="xl" onHide={handleCancel}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Configure Rqbit desktop</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<Modal
|
||||
title="Configure Rqbit desktop"
|
||||
isOpen={show}
|
||||
onClose={handleCancel}
|
||||
className="max-w-4xl"
|
||||
>
|
||||
<ModalBody>
|
||||
<ErrorComponent error={error}></ErrorComponent>
|
||||
<Tabs defaultActiveKey="home" id="rqbit-config" className="mb-3">
|
||||
<Tab className="mb-3" eventKey="home" title="Home">
|
||||
<FormInput
|
||||
label="Default download folder"
|
||||
name="default_download_location"
|
||||
value={config.default_download_location}
|
||||
inputType="text"
|
||||
onChange={handleInputChange}
|
||||
help="Where to download torrents by default. You can override this per torrent."
|
||||
/>
|
||||
</Tab>
|
||||
<div className="flex border-b mb-4">
|
||||
{TABS.map((t, i) => {
|
||||
const isActive = t === tab;
|
||||
let classNames = "text-slate-300";
|
||||
if (isActive) {
|
||||
classNames = "text-slate-800 border-b-2 border-blue-800";
|
||||
}
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
className={`p-2 ${classNames}`}
|
||||
onClick={() => setTab(t)}
|
||||
>
|
||||
{t}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<Tab className="mb-3" eventKey="dht" title="DHT">
|
||||
<legend>DHT config</legend>
|
||||
<Tab name="Home" currentTab={tab}>
|
||||
<FormInput
|
||||
label="Default download folder"
|
||||
name="default_download_location"
|
||||
value={config.default_download_location}
|
||||
inputType="text"
|
||||
onChange={handleInputChange}
|
||||
help="Where to download torrents by default. You can override this per torrent."
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab name="DHT" currentTab={tab}>
|
||||
<Fieldset label="DHT config">
|
||||
<FormCheck
|
||||
label="Enable DHT"
|
||||
name="dht.disable"
|
||||
|
|
@ -190,11 +237,11 @@ export const ConfigModal: React.FC<{
|
|||
onChange={handleInputChange}
|
||||
help="The filename to store DHT state into"
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab className="mb-3" eventKey="tcp_listen" title="TCP">
|
||||
<legend>TCP Listener config</legend>
|
||||
</Fieldset>
|
||||
</Tab>
|
||||
|
||||
<Tab name="TCP Listen" currentTab={tab}>
|
||||
<Fieldset label="TCP Listener config">
|
||||
<FormCheck
|
||||
label="Listen on TCP"
|
||||
name="tcp_listen.disable"
|
||||
|
|
@ -230,11 +277,11 @@ export const ConfigModal: React.FC<{
|
|||
onChange={handleInputChange}
|
||||
help="The max port to try to listen on."
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab className="mb-3" eventKey="session_persistence" title="Session">
|
||||
<legend>Session persistence</legend>
|
||||
</Fieldset>
|
||||
</Tab>
|
||||
|
||||
<Tab name="Session" currentTab={tab}>
|
||||
<Fieldset label="Session persistence">
|
||||
<FormCheck
|
||||
label="Enable persistence"
|
||||
name="persistence.disable"
|
||||
|
|
@ -251,11 +298,11 @@ export const ConfigModal: React.FC<{
|
|||
onChange={handleInputChange}
|
||||
disabled={config.persistence.disable}
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab className="mb-3" eventKey="peer_opts" title="Peer options">
|
||||
<legend>Peer connection options</legend>
|
||||
</Fieldset>
|
||||
</Tab>
|
||||
|
||||
<Tab name="Peer options" currentTab={tab}>
|
||||
<Fieldset label="Peer connection options">
|
||||
<FormInput
|
||||
label="Connect timeout (seconds)"
|
||||
inputType="number"
|
||||
|
|
@ -273,11 +320,11 @@ export const ConfigModal: React.FC<{
|
|||
onChange={handleInputChange}
|
||||
help="Peer socket read/write timeout."
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab className="mb-3" eventKey="http_api" title="HTTP API">
|
||||
<legend>HTTP API config</legend>
|
||||
</Fieldset>
|
||||
</Tab>
|
||||
|
||||
<Tab name="HTTP API" currentTab={tab}>
|
||||
<Fieldset label="HTTP API config">
|
||||
<FormCheck
|
||||
label="Enable HTTP API"
|
||||
name="http_api.disable"
|
||||
|
|
@ -313,10 +360,10 @@ export const ConfigModal: React.FC<{
|
|||
onChange={handleInputChange}
|
||||
help={`You'll access the API at http://${config.http_api.listen_addr}`}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
</Fieldset>
|
||||
</Tab>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
{!!handleCancel && (
|
||||
<Button variant="secondary" onClick={handleCancel}>
|
||||
Cancel
|
||||
|
|
@ -328,7 +375,7 @@ export const ConfigModal: React.FC<{
|
|||
<Button variant="primary" onClick={handleOkClick} disabled={loading}>
|
||||
OK
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client";
|
|||
import { invoke } from "@tauri-apps/api";
|
||||
import { CurrentDesktopState, RqbitDesktopConfig } from "./configuration";
|
||||
import { RqbitDesktop } from "./rqbit-desktop";
|
||||
import "./styles/index.css";
|
||||
|
||||
async function get_version(): Promise<string> {
|
||||
return invoke<string>("get_version");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useState } from "react";
|
|||
import { RqbitWebUI } from "rqbit-webui/src/rqbit-web";
|
||||
import { CurrentDesktopState, RqbitDesktopConfig } from "./configuration";
|
||||
import { ConfigModal } from "./configure";
|
||||
import { IconButton } from "rqbit-webui/src/components/IconButton";
|
||||
import { IconButton } from "rqbit-webui/src/components/buttons/IconButton";
|
||||
import { BsSliders2 } from "react-icons/bs";
|
||||
import { APIContext } from "rqbit-webui/src/context";
|
||||
import { makeAPI } from "./api";
|
||||
|
|
@ -20,7 +20,6 @@ export const RqbitDesktop: React.FC<{
|
|||
|
||||
const configButton = (
|
||||
<IconButton
|
||||
className="p-3 text-primary"
|
||||
onClick={() => {
|
||||
setConfigurationOpened(true);
|
||||
}}
|
||||
|
|
@ -33,7 +32,7 @@ export const RqbitDesktop: React.FC<{
|
|||
<APIContext.Provider value={makeAPI(config)}>
|
||||
{configured && (
|
||||
<RqbitWebUI
|
||||
title={`Rqbit Desktop v${version}`}
|
||||
title={`Rqbit Desktop - v${version}`}
|
||||
menuButtons={[configButton]}
|
||||
></RqbitWebUI>
|
||||
)}
|
||||
|
|
|
|||
3
desktop/src/styles/index.css
Normal file
3
desktop/src/styles/index.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
Loading…
Add table
Add a link
Reference in a new issue