mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-02-27 04:06:39 +00:00
Migrate ServersListGroup to tailwind components
This commit is contained in:
@@ -45,7 +45,7 @@ export const Home = ({ servers }: HomeProps) => {
|
||||
>
|
||||
Welcome!
|
||||
</h1>
|
||||
<ServersListGroup embedded servers={serversList}>
|
||||
<ServersListGroup servers={serversList}>
|
||||
{!hasServers && (
|
||||
<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>
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
@use '../../node_modules/@shlinkio/shlink-frontend-kit/dist/base';
|
||||
@use '../utils/mixins/vertical-align';
|
||||
@use '../utils/mixins/thin-scroll';
|
||||
|
||||
.servers-list__list-group.servers-list__list-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.servers-list__list-group:not(.servers-list__list-group--embedded) {
|
||||
max-width: 400px;
|
||||
box-shadow: 0 .125rem .25rem rgb(0 0 0 / .075);
|
||||
}
|
||||
|
||||
.servers-list__server-item.servers-list__server-item {
|
||||
text-align: left;
|
||||
position: relative;
|
||||
padding: .75rem 2.5rem .75rem 1rem;
|
||||
}
|
||||
|
||||
.servers-list__server-item:not(:hover) {
|
||||
color: base.$mainColor;
|
||||
}
|
||||
|
||||
.servers-list__server-item:hover {
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.servers-list__server-item-icon {
|
||||
@include vertical-align.vertical-align();
|
||||
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
.servers-list__list-group--embedded.servers-list__list-group--embedded {
|
||||
border-radius: 0;
|
||||
border-top: 1px solid var(--border-color);
|
||||
|
||||
@media (min-width: base.$mdMin) {
|
||||
max-height: 220px;
|
||||
overflow-x: auto;
|
||||
|
||||
@include thin-scroll.thin-scroll();
|
||||
}
|
||||
|
||||
.servers-list__server-item {
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,42 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { clsx } from 'clsx';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { ListGroup, ListGroupItem } from 'reactstrap';
|
||||
import type { ServerWithId } from './data';
|
||||
import './ServersListGroup.scss';
|
||||
|
||||
type ServersListGroupProps = PropsWithChildren<{
|
||||
servers: ServerWithId[];
|
||||
embedded?: boolean;
|
||||
borderless?: boolean;
|
||||
}>;
|
||||
|
||||
const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
||||
<ListGroupItem tag={Link} to={`/server/${id}`} className="servers-list__server-item">
|
||||
{name}
|
||||
<FontAwesomeIcon icon={chevronIcon} className="servers-list__server-item-icon" />
|
||||
</ListGroupItem>
|
||||
<Link
|
||||
to={`/server/${id}`}
|
||||
className={clsx(
|
||||
'servers-list__server-item',
|
||||
'tw:flex tw:items-center tw:justify-between tw:gap-x-2 tw:px-4 tw:py-3',
|
||||
'tw:rounded-none tw:hover:bg-lm-secondary tw:hover:dark:bg-dm-secondary',
|
||||
'tw:border-b tw:last:border-0 tw:border-lm-border tw:dark:border-dm-border',
|
||||
)}
|
||||
>
|
||||
<span className="tw:truncate">{name}</span>
|
||||
<FontAwesomeIcon icon={chevronIcon} />
|
||||
</Link>
|
||||
);
|
||||
|
||||
export const ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, embedded = false }) => (
|
||||
export const ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, borderless }) => (
|
||||
<>
|
||||
{children && <div data-testid="title" className="mb-0 fs-5 fw-normal lh-sm">{children}</div>}
|
||||
{children && <div data-testid="title" className="fs-5 fw-normal lh-sm">{children}</div>}
|
||||
{servers.length > 0 && (
|
||||
<ListGroup
|
||||
<div
|
||||
data-testid="list"
|
||||
tag="div"
|
||||
className={clsx('servers-list__list-group', { 'servers-list__list-group--embedded': embedded })}
|
||||
className={clsx(
|
||||
'tw:w-full tw:border-lm-border tw:dark:border-dm-border',
|
||||
'tw:md:max-h-56 tw:md:overflow-y-auto tw:-mb-1 tw:scroll-thin',
|
||||
{ 'tw:border-y': !borderless },
|
||||
)}
|
||||
>
|
||||
{servers.map(({ id, name }) => <ServerListItem key={id} id={id} name={name} />)}
|
||||
</ListGroup>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Message } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Card, Message } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import type { FC } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
||||
@@ -35,18 +35,20 @@ const ServerError: FCWithDeps<ServerErrorProps, ServerErrorDeps> = ({ servers, s
|
||||
)}
|
||||
</Message>
|
||||
|
||||
<ServersListGroup servers={Object.values(servers)}>
|
||||
<p className="mb-md-3">
|
||||
These are the Shlink servers currently configured. Choose one of
|
||||
them or <Link to="/server/create">add a new one</Link>.
|
||||
</p>
|
||||
</ServersListGroup>
|
||||
<p className="tw:text-xl">
|
||||
These are the Shlink servers currently configured. Choose one of
|
||||
them or <Link to="/server/create">add a new one</Link>.
|
||||
</p>
|
||||
<Card className="tw:w-full tw:max-w-100 tw:overflow-hidden tw:mt-4">
|
||||
<ServersListGroup borderless servers={Object.values(servers)} />
|
||||
</Card>
|
||||
|
||||
{isServerWithId(selectedServer) && (
|
||||
<div className="container mt-3 mt-md-5">
|
||||
<p className="fs-5 fw-normal lh-sm">
|
||||
<p className="tw:text-xl">
|
||||
Alternatively, if you think you may have misconfigured this server, you
|
||||
can <DeleteServerButton server={selectedServer} className="server-error__delete-btn">remove it</DeleteServerButton> or
|
||||
can <DeleteServerButton server={selectedServer} className="server-error__delete-btn">remove
|
||||
it</DeleteServerButton> or
|
||||
<Link to={`/server/${selectedServer.id}/edit?reconnect=true`}>edit it</Link>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
@import 'tailwindcss' prefix(tw) important;
|
||||
@source '../node_modules/@shlinkio/shlink-frontend-kit';
|
||||
@import '@shlinkio/shlink-frontend-kit/tailwind.preset.css';
|
||||
|
||||
@utility scroll-thin {
|
||||
/* Standard. New browsers */
|
||||
scrollbar-width: thin;
|
||||
|
||||
/* Fallback */
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
@mixin thin-scroll() {
|
||||
/* Forefox scrollbar */
|
||||
scrollbar-color: rgba(0, 0, 0, .2) #f5f5f5;
|
||||
scrollbar-width: thin;
|
||||
|
||||
/* Chrome webkit scrollbar */
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,12 @@ describe('<ServersListGroup />', () => {
|
||||
fromPartial({ name: 'foo', id: '123' }),
|
||||
fromPartial({ name: 'bar', id: '456' }),
|
||||
];
|
||||
const setUp = (params: { servers?: ServerWithId[]; withChildren?: boolean; embedded?: boolean } = {}) => {
|
||||
const { servers = [], withChildren = true, embedded } = params;
|
||||
const setUp = (params: { servers?: ServerWithId[]; withChildren?: boolean; borderless?: boolean } = {}) => {
|
||||
const { servers = [], withChildren = true, borderless } = params;
|
||||
|
||||
return render(
|
||||
<MemoryRouter>
|
||||
<ServersListGroup servers={servers} embedded={embedded}>
|
||||
<ServersListGroup servers={servers} borderless={borderless}>
|
||||
{withChildren ? 'The list of servers' : undefined}
|
||||
</ServersListGroup>
|
||||
</MemoryRouter>,
|
||||
@@ -45,11 +45,17 @@ describe('<ServersListGroup />', () => {
|
||||
});
|
||||
|
||||
it.each([
|
||||
[true, 'servers-list__list-group servers-list__list-group--embedded'],
|
||||
[false, 'servers-list__list-group'],
|
||||
[undefined, 'servers-list__list-group'],
|
||||
])('renders proper classes for embedded', (embedded, expectedClasses) => {
|
||||
setUp({ servers, embedded });
|
||||
expect(screen.getByTestId('list')).toHaveAttribute('class', `${expectedClasses} list-group`);
|
||||
[true],
|
||||
[false],
|
||||
[undefined],
|
||||
])('renders proper classes for embedded', (borderless) => {
|
||||
setUp({ servers, borderless });
|
||||
const list = screen.getByTestId('list');
|
||||
|
||||
if (!borderless) {
|
||||
expect(list).toHaveClass('tw:border-y');
|
||||
} else {
|
||||
expect(list).not.toHaveClass('tw:border-y');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user