Replace most stylesheets with tailwind styles

This commit is contained in:
Alejandro Celaya
2025-04-03 10:46:32 +02:00
parent aefe5e0848
commit fd40e2b7bc
11 changed files with 39 additions and 91 deletions

View File

@@ -1,22 +0,0 @@
.main-header.main-header {
color: white;
background-color: var(--brand-color) !important;
.navbar-brand {
color: inherit !important;
}
}
.main-header__brand-logo {
width: 26px;
margin-right: 5px;
}
.main-header__toggle-icon {
width: 20px;
transition: transform 300ms;
}
.main-header__toggle-icon--opened {
transform: rotate(180deg);
}

View File

@@ -9,7 +9,6 @@ import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } f
import type { FCWithDeps } from '../container/utils'; import type { FCWithDeps } from '../container/utils';
import { componentFactory, useDependencies } from '../container/utils'; import { componentFactory, useDependencies } from '../container/utils';
import { ShlinkLogo } from './img/ShlinkLogo'; import { ShlinkLogo } from './img/ShlinkLogo';
import './MainHeader.scss';
type MainHeaderDeps = { type MainHeaderDeps = {
ServersDropdown: FC; ServersDropdown: FC;
@@ -25,20 +24,22 @@ const MainHeader: FCWithDeps<unknown, MainHeaderDeps> = () => {
useEffect(collapse, [location, collapse]); useEffect(collapse, [location, collapse]);
const settingsPath = '/settings'; const settingsPath = '/settings';
const toggleClass = clsx('main-header__toggle-icon', { 'main-header__toggle-icon--opened': isNotCollapsed });
return ( return (
<Navbar color="primary" dark fixed="top" className="main-header" expand="md"> <Navbar color="primary" dark fixed="top" expand="md" className="tw:text-white tw:bg-lm-brand tw:dark:bg-dm-brand">
<NavbarBrand tag={Link} to="/"> <NavbarBrand tag={Link} to="/">
<ShlinkLogo className="main-header__brand-logo tw:inline" color="white" /> Shlink <ShlinkLogo className="tw:inline tw:w-7 tw:mr-1" color="white" /> Shlink
</NavbarBrand> </NavbarBrand>
<NavbarToggler onClick={toggleCollapse}> <NavbarToggler onClick={toggleCollapse}>
<FontAwesomeIcon icon={arrowIcon} className={toggleClass} /> <FontAwesomeIcon
icon={arrowIcon}
className={clsx('tw:transition-transform tw:duration-300', { 'tw:rotate-180': isNotCollapsed })}
/>
</NavbarToggler> </NavbarToggler>
<Collapse navbar isOpen={isNotCollapsed}> <Collapse navbar isOpen={isNotCollapsed}>
<Nav navbar className="ms-auto"> <Nav navbar className="tw:ml-auto">
<NavItem> <NavItem>
<NavLink tag={Link} to={settingsPath} active={pathname.startsWith(settingsPath)}> <NavLink tag={Link} to={settingsPath} active={pathname.startsWith(settingsPath)}>
<FontAwesomeIcon icon={cogsIcon} />&nbsp; Settings <FontAwesomeIcon icon={cogsIcon} />&nbsp; Settings

View File

@@ -1,9 +0,0 @@
@use '../../node_modules/@shlinkio/shlink-frontend-kit/dist/base';
.shlink-versions-container--with-sidebar {
margin-left: 0;
@media (min-width: base.$mdMin) {
margin-left: base.$asideMenuWidth;
}
}

View File

@@ -2,7 +2,6 @@ import { clsx } from 'clsx';
import type { SelectedServer } from '../servers/data'; import type { SelectedServer } from '../servers/data';
import { isReachableServer } from '../servers/data'; import { isReachableServer } from '../servers/data';
import { ShlinkVersions } from './ShlinkVersions'; import { ShlinkVersions } from './ShlinkVersions';
import './ShlinkVersionsContainer.scss';
export type ShlinkVersionsContainerProps = { export type ShlinkVersionsContainerProps = {
selectedServer: SelectedServer; selectedServer: SelectedServer;
@@ -10,9 +9,7 @@ export type ShlinkVersionsContainerProps = {
export const ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => ( export const ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => (
<div <div
className={clsx('text-center', { className={clsx('text-center', { 'tw:md:ml-(--aside-menu-width)': isReachableServer(selectedServer) })}
'shlink-versions-container--with-sidebar': isReachableServer(selectedServer),
})}
> >
<ShlinkVersions selectedServer={selectedServer} /> <ShlinkVersions selectedServer={selectedServer} />
</div> </div>

View File

@@ -1,17 +0,0 @@
@use '../../../node_modules/@shlinkio/shlink-frontend-kit/dist/base';
.server-error__container {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.server-error__delete-btn {
color: base.$dangerColor;
font-weight: inherit;
}
.server-error__delete-btn:hover {
text-decoration: underline;
}

View File

@@ -8,7 +8,6 @@ import type { SelectedServer, ServersMap } from '../data';
import { isServerWithId } from '../data'; import { isServerWithId } from '../data';
import type { DeleteServerButtonProps } from '../DeleteServerButton'; import type { DeleteServerButtonProps } from '../DeleteServerButton';
import { ServersListGroup } from '../ServersListGroup'; import { ServersListGroup } from '../ServersListGroup';
import './ServerError.scss';
type ServerErrorProps = { type ServerErrorProps = {
servers: ServersMap; servers: ServersMap;
@@ -24,8 +23,8 @@ const ServerError: FCWithDeps<ServerErrorProps, ServerErrorDeps> = ({ servers, s
return ( return (
<NoMenuLayout> <NoMenuLayout>
<div className="server-error__container flex-column"> <div className="tw:flex tw:flex-col tw:items-center tw:gap-y-4 tw:md:gap-y-8">
<Message className="w-100 mb-3 mb-md-5" variant="error"> <Message className="tw:w-full tw:lg:w-[80%]" variant="error">
{!isServerWithId(selectedServer) && 'Could not find this Shlink server.'} {!isServerWithId(selectedServer) && 'Could not find this Shlink server.'}
{isServerWithId(selectedServer) && ( {isServerWithId(selectedServer) && (
<> <>
@@ -39,19 +38,17 @@ const ServerError: FCWithDeps<ServerErrorProps, ServerErrorDeps> = ({ servers, s
These are the Shlink servers currently configured. Choose one of These are the Shlink servers currently configured. Choose one of
them or <Link to="/server/create">add a new one</Link>. them or <Link to="/server/create">add a new one</Link>.
</p> </p>
<Card className="tw:w-full tw:max-w-100 tw:overflow-hidden tw:mt-4"> <Card className="tw:w-full tw:max-w-100 tw:overflow-hidden">
<ServersListGroup borderless servers={Object.values(servers)} /> <ServersListGroup borderless servers={Object.values(servers)} />
</Card> </Card>
{isServerWithId(selectedServer) && ( {isServerWithId(selectedServer) && (
<div className="container mt-3 mt-md-5">
<p className="tw:text-xl"> <p className="tw:text-xl">
Alternatively, if you think you may have misconfigured this server, you Alternatively, if you think you may have misconfigured this server, you
can <DeleteServerButton server={selectedServer} className="server-error__delete-btn">remove can <DeleteServerButton server={selectedServer} className="tw:text-danger tw:hover:underline">remove
it</DeleteServerButton> or&nbsp; it</DeleteServerButton> or&nbsp;
<Link to={`/server/${selectedServer.id}/edit?reconnect=true`}>edit it</Link>. <Link to={`/server/${selectedServer.id}/edit?reconnect=true`}>edit it</Link>.
</p> </p>
</div>
)} )}
</div> </div>
</NoMenuLayout> </NoMenuLayout>

View File

@@ -14,3 +14,11 @@
border-radius: .5rem; border-radius: .5rem;
} }
} }
@layer base {
:root {
--header-height: 56px;
/* Width of ShlinkWebComponent's side menu when not collapsed */
--aside-menu-width: 260px;
}
}

View File

@@ -1,5 +0,0 @@
@mixin horizontal-align {
position: absolute;
left: 50%;
transform: translateX(-50%);
}

View File

@@ -1,5 +0,0 @@
@mixin vertical-align($extraTransforms: null) {
position: absolute;
top: 50%;
transform: translateY(-50%) $extraTransforms;
}

View File

@@ -51,14 +51,12 @@ describe('<MainHeader />', () => {
const toggle = screen.getByLabelText('Toggle navigation'); const toggle = screen.getByLabelText('Toggle navigation');
const icon = toggle.firstChild; const icon = toggle.firstChild;
expect(icon).toHaveAttribute('class', expect.stringMatching(/main-header__toggle-icon$/)); expect(icon).not.toHaveClass('tw:rotate-180');
await user.click(toggle); await user.click(toggle);
expect(icon).toHaveAttribute(
'class', expect(icon).toHaveClass('tw:rotate-180');
expect.stringMatching(/main-header__toggle-icon main-header__toggle-icon--opened$/),
);
await user.click(toggle); await user.click(toggle);
expect(icon).toHaveAttribute('class', expect.stringMatching(/main-header__toggle-icon$/)); expect(icon).not.toHaveClass('tw:rotate-180');
}); });
it('opens Collapse when clicking toggle', async () => { it('opens Collapse when clicking toggle', async () => {

View File

@@ -16,11 +16,16 @@ describe('<ShlinkVersionsContainer />', () => {
])('passes a11y checks', (selectedServer) => checkAccessibility(setUp(selectedServer))); ])('passes a11y checks', (selectedServer) => checkAccessibility(setUp(selectedServer)));
it.each([ it.each([
[null, 'text-center'], [null, false],
[fromPartial<SelectedServer>({}), 'text-center'], [fromPartial<SelectedServer>({}), false],
[fromPartial<ReachableServer>({ version: '1.0.0' }), 'text-center shlink-versions-container--with-sidebar'], [fromPartial<ReachableServer>({ version: '1.0.0' }), true],
])('renders proper col classes based on sidebar status', (selectedServer, expectedClasses) => { ])('renders proper col classes based on sidebar status', (selectedServer, shouldAddMargin) => {
const { container } = setUp(selectedServer); const { container } = setUp(selectedServer);
expect(container.firstChild).toHaveAttribute('class', `${expectedClasses}`);
if (shouldAddMargin) {
expect(container.firstChild).toHaveClass('tw:md:ml-(--aside-menu-width)');
} else {
expect(container.firstChild).not.toHaveClass('tw:md:ml-(--aside-menu-width)');
}
}); });
}); });