mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-15 03:53:51 +00:00
Replace all remaining bootstrap utility classes with tailwind classes
This commit is contained in:
@@ -45,26 +45,24 @@ export const Home = ({ servers }: HomeProps) => {
|
|||||||
>
|
>
|
||||||
Welcome!
|
Welcome!
|
||||||
</h1>
|
</h1>
|
||||||
<ServersListGroup servers={serversList}>
|
{hasServers ? <ServersListGroup servers={serversList} /> : (
|
||||||
{!hasServers && (
|
<div className="tw:p-6 tw:text-center tw:flex tw:flex-col tw:gap-12 tw:text-xl">
|
||||||
<div className="tw:p-6 tw:text-center tw:flex tw:flex-col tw:gap-12">
|
<p>This application will help you manage your Shlink servers.</p>
|
||||||
<p>This application will help you manage your Shlink servers.</p>
|
<p>
|
||||||
<p>
|
<Button to="/server/create" size="lg" inline>
|
||||||
<Button to="/server/create" size="lg" inline>
|
<FontAwesomeIcon icon={faPlus} /> Add a server
|
||||||
<FontAwesomeIcon icon={faPlus} /> Add a server
|
</Button>
|
||||||
</Button>
|
</p>
|
||||||
</p>
|
<p>
|
||||||
<p>
|
<ExternalLink href="https://shlink.io/documentation">
|
||||||
<ExternalLink href="https://shlink.io/documentation">
|
<small>
|
||||||
<small>
|
<span className="tw:mr-2">Learn more about Shlink</span>
|
||||||
<span className="tw:mr-2">Learn more about Shlink</span>
|
<FontAwesomeIcon icon={faExternalLinkAlt} />
|
||||||
<FontAwesomeIcon icon={faExternalLinkAlt} />
|
</small>
|
||||||
</small>
|
</ExternalLink>
|
||||||
</ExternalLink>
|
</p>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
</ServersListGroup>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -63,13 +63,17 @@ const ManageServers: FCWithDeps<ManageServersProps, ManageServersDeps> = ({ serv
|
|||||||
<SimpleCard className="card">
|
<SimpleCard className="card">
|
||||||
<Table header={(
|
<Table header={(
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
{hasAutoConnect && <Table.Cell style={{ width: '50px' }}><span className="sr-only">Auto-connect</span></Table.Cell>}
|
{hasAutoConnect && (
|
||||||
|
<Table.Cell className="tw:w-[35px]"><span className="tw:sr-only">Auto-connect</span></Table.Cell>
|
||||||
|
)}
|
||||||
<Table.Cell>Name</Table.Cell>
|
<Table.Cell>Name</Table.Cell>
|
||||||
<Table.Cell>Base URL</Table.Cell>
|
<Table.Cell>Base URL</Table.Cell>
|
||||||
<Table.Cell><span className="sr-only">Options</span></Table.Cell>
|
<Table.Cell><span className="sr-only">Options</span></Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
)}>
|
)}>
|
||||||
{!filteredServers.length && <Table.Row className="text-center"><Table.Cell colSpan={4}>No servers found.</Table.Cell></Table.Row>}
|
{!filteredServers.length && (
|
||||||
|
<Table.Row className="tw:text-center"><Table.Cell colSpan={4}>No servers found.</Table.Cell></Table.Row>
|
||||||
|
)}
|
||||||
{filteredServers.map((server) => (
|
{filteredServers.map((server) => (
|
||||||
<ManageServersRow key={server.id} server={server} hasAutoConnect={hasAutoConnect} />
|
<ManageServersRow key={server.id} server={server} hasAutoConnect={hasAutoConnect} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const ManageServersRow: FCWithDeps<ManageServersRowProps, ManageServersRowDeps>
|
|||||||
<Table.Cell columnName="Auto-connect">
|
<Table.Cell columnName="Auto-connect">
|
||||||
{server.autoConnect && (
|
{server.autoConnect && (
|
||||||
<>
|
<>
|
||||||
<FontAwesomeIcon icon={checkIcon} className="text-primary" id="autoConnectIcon" />
|
<FontAwesomeIcon icon={checkIcon} className="tw:text-brand" id="autoConnectIcon" />
|
||||||
<UncontrolledTooltip target="autoConnectIcon" placement="right">
|
<UncontrolledTooltip target="autoConnectIcon" placement="right">
|
||||||
Auto-connect to this server
|
Auto-connect to this server
|
||||||
</UncontrolledTooltip>
|
</UncontrolledTooltip>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProp
|
|||||||
if (serversList.length === 0) {
|
if (serversList.length === 0) {
|
||||||
return (
|
return (
|
||||||
<DropdownItem tag={Link} to="/server/create">
|
<DropdownItem tag={Link} to="/server/create">
|
||||||
<FontAwesomeIcon icon={plusIcon} /> <span className="ms-1">Add a server</span>
|
<FontAwesomeIcon icon={plusIcon} /> <span className="tw:ml-1">Add a server</span>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProp
|
|||||||
))}
|
))}
|
||||||
<DropdownItem divider tag="hr" />
|
<DropdownItem divider tag="hr" />
|
||||||
<DropdownItem tag={Link} to="/manage-servers">
|
<DropdownItem tag={Link} to="/manage-servers">
|
||||||
<FontAwesomeIcon icon={serverIcon} /> <span className="ms-1">Manage servers</span>
|
<FontAwesomeIcon icon={serverIcon} /> <span className="tw:ml-1">Manage servers</span>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -40,9 +40,9 @@ export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProp
|
|||||||
return (
|
return (
|
||||||
<UncontrolledDropdown nav inNavbar>
|
<UncontrolledDropdown nav inNavbar>
|
||||||
<DropdownToggle nav caret>
|
<DropdownToggle nav caret>
|
||||||
<FontAwesomeIcon icon={serverIcon} /> <span className="ms-1">Servers</span>
|
<FontAwesomeIcon icon={serverIcon} /> <span className="tw:ml-1">Servers</span>
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu end style={{ right: 0 }}>{renderServers()}</DropdownMenu>
|
<DropdownMenu end classNam="tw:right-0">{renderServers()}</DropdownMenu>
|
||||||
</UncontrolledDropdown>
|
</UncontrolledDropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { clsx } from 'clsx';
|
import { clsx } from 'clsx';
|
||||||
import type { FC, PropsWithChildren } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import type { ServerWithId } from './data';
|
import type { ServerWithId } from './data';
|
||||||
|
|
||||||
type ServersListGroupProps = PropsWithChildren<{
|
type ServersListGroupProps = {
|
||||||
servers: ServerWithId[];
|
servers: ServerWithId[];
|
||||||
borderless?: boolean;
|
borderless?: boolean;
|
||||||
}>;
|
};
|
||||||
|
|
||||||
const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
||||||
<Link
|
<Link
|
||||||
@@ -25,9 +25,8 @@ const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, borderless }) => (
|
export const ServersListGroup: FC<ServersListGroupProps> = ({ servers, borderless }) => (
|
||||||
<>
|
<>
|
||||||
{children && <div data-testid="title" className="fs-5 fw-normal lh-sm">{children}</div>}
|
|
||||||
{servers.length > 0 && (
|
{servers.length > 0 && (
|
||||||
<div
|
<div
|
||||||
data-testid="list"
|
data-testid="list"
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept=".csv"
|
accept=".csv"
|
||||||
className="d-none"
|
className="tw:hidden"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
ref={ref as any /* TODO Remove After updating to React 19 */}
|
ref={ref as any /* TODO Remove After updating to React 19 */}
|
||||||
onChange={onFile}
|
onChange={onFile}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, child
|
|||||||
const handleSubmit = handleEventPreventingDefault(() => onSubmit({ name, url, apiKey }));
|
const handleSubmit = handleEventPreventingDefault(() => onSubmit({ name, url, apiKey }));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="server-form" name="serverForm" onSubmit={handleSubmit}>
|
<form name="serverForm" onSubmit={handleSubmit}>
|
||||||
<SimpleCard className="tw:mb-4" bodyClassName="tw:flex tw:flex-col tw:gap-y-3" title={title}>
|
<SimpleCard className="tw:mb-4" bodyClassName="tw:flex tw:flex-col tw:gap-y-3" title={title}>
|
||||||
<LabelledInput label="Name" value={name} onChange={(e) => setName(e.target.value)} required />
|
<LabelledInput label="Name" value={name} onChange={(e) => setName(e.target.value)} required />
|
||||||
<LabelledInput label="URL" type="url" value={url} onChange={(e) => setUrl(e.target.value)} required />
|
<LabelledInput label="URL" type="url" value={url} onChange={(e) => setUrl(e.target.value)} required />
|
||||||
|
|||||||
@@ -10,30 +10,18 @@ describe('<ServersListGroup />', () => {
|
|||||||
fromPartial({ name: 'foo', id: '123' }),
|
fromPartial({ name: 'foo', id: '123' }),
|
||||||
fromPartial({ name: 'bar', id: '456' }),
|
fromPartial({ name: 'bar', id: '456' }),
|
||||||
];
|
];
|
||||||
const setUp = (params: { servers?: ServerWithId[]; withChildren?: boolean; borderless?: boolean } = {}) => {
|
const setUp = (params: { servers?: ServerWithId[]; borderless?: boolean } = {}) => {
|
||||||
const { servers = [], withChildren = true, borderless } = params;
|
const { servers = [], borderless } = params;
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ServersListGroup servers={servers} borderless={borderless}>
|
<ServersListGroup servers={servers} borderless={borderless} />
|
||||||
{withChildren ? 'The list of servers' : undefined}
|
|
||||||
</ServersListGroup>
|
|
||||||
</MemoryRouter>,
|
</MemoryRouter>,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||||
|
|
||||||
it('renders title', () => {
|
|
||||||
setUp({});
|
|
||||||
expect(screen.getByTestId('title')).toHaveTextContent('The list of servers');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not render title when children is not provided', () => {
|
|
||||||
setUp({ withChildren: false });
|
|
||||||
expect(screen.queryByTestId('title')).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[servers],
|
[servers],
|
||||||
[[]],
|
[[]],
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ exports[`<ManageServersRow /> > renders auto-connect icon only if server is auto
|
|||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="svg-inline--fa fa-check text-primary"
|
class="svg-inline--fa fa-check tw:text-brand"
|
||||||
data-icon="check"
|
data-icon="check"
|
||||||
data-prefix="fas"
|
data-prefix="fas"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
|
|||||||
Reference in New Issue
Block a user