mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-04-23 06:56:22 +00:00
Update to latest shlink-frontend-kit and shlink-web-component
This commit is contained in:
@@ -61,15 +61,15 @@ const App: FCWithDeps<AppProps, AppDeps> = (
|
||||
}, [settings.ui?.theme]);
|
||||
|
||||
return (
|
||||
<div className="tw:h-full">
|
||||
<div className="h-full">
|
||||
<MainHeader />
|
||||
|
||||
<div className="tw:h-full tw:pt-(--tw-header-height)">
|
||||
<div className="h-full pt-(--header-height)">
|
||||
<div
|
||||
data-testid="shlink-wrapper"
|
||||
className={clsx(
|
||||
'tw:min-h-full tw:pb-[calc(var(--footer-height)+var(--footer-margin))] tw:-mb-[calc(var(--footer-height)+var(--footer-margin))]',
|
||||
{ 'tw:flex tw:items-center tw:pt-4': isHome },
|
||||
'min-h-full pb-[calc(var(--footer-height)+var(--footer-margin))] -mb-[calc(var(--footer-height)+var(--footer-margin))]',
|
||||
{ 'flex items-center pt-4': isHome },
|
||||
)}
|
||||
>
|
||||
<Routes>
|
||||
@@ -87,7 +87,7 @@ const App: FCWithDeps<AppProps, AppDeps> = (
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<div className="tw:h-(--footer-height) tw:mt-(--footer-margin) tw:md:px-4">
|
||||
<div className="h-(--footer-height) mt-(--footer-margin) md:px-4">
|
||||
<ShlinkVersionsContainer />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { Button, Card, CloseButton } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button, Card, CloseButton,useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { clsx } from 'clsx';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
@@ -13,7 +12,7 @@ interface AppUpdateBannerProps {
|
||||
}
|
||||
|
||||
export const AppUpdateBanner: FC<AppUpdateBannerProps> = ({ isOpen, onClose, forceUpdate }) => {
|
||||
const { flag: isUpdating, setToTrue: setUpdating } = useToggle(false, true);
|
||||
const { flag: isUpdating, setToTrue: setUpdating } = useToggle();
|
||||
const update = useCallback(() => {
|
||||
setUpdating();
|
||||
forceUpdate();
|
||||
@@ -27,15 +26,15 @@ export const AppUpdateBanner: FC<AppUpdateBannerProps> = ({ isOpen, onClose, for
|
||||
<Card
|
||||
role="alert"
|
||||
className={clsx(
|
||||
'tw:w-[700px] tw:max-w-[calc(100%-30px)]',
|
||||
'tw:fixed tw:top-[35px] tw:left-[50%] tw:translate-x-[-50%] tw:z-[1040]',
|
||||
'w-[700px] max-w-[calc(100%-30px)]',
|
||||
'fixed top-[35px] left-[50%] translate-x-[-50%] z-[1040]',
|
||||
)}
|
||||
>
|
||||
<Card.Header className="tw:flex tw:items-center tw:justify-between">
|
||||
<Card.Header className="flex items-center justify-between">
|
||||
<h5>This app has just been updated!</h5>
|
||||
<CloseButton onClick={onClose} />
|
||||
</Card.Header>
|
||||
<Card.Body className="tw:flex tw:gap-4 tw:items-center tw:justify-between tw:max-md:flex-col">
|
||||
<Card.Body className="flex gap-4 items-center justify-between max-md:flex-col">
|
||||
Restart it to enjoy the new features.
|
||||
<Button disabled={isUpdating} variant="secondary" solid onClick={update}>
|
||||
{!isUpdating && <>Restart now <FontAwesomeIcon icon={reloadIcon} /></>}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { PropsWithChildren, ReactNode } from 'react';
|
||||
import { Component } from 'react';
|
||||
import { ErrorLayout } from './ErrorLayout';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SimpleCard } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { SimpleCard } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
|
||||
export type ErrorLayoutProps = PropsWithChildren<{
|
||||
@@ -6,8 +6,8 @@ export type ErrorLayoutProps = PropsWithChildren<{
|
||||
}>;
|
||||
|
||||
export const ErrorLayout: FC<ErrorLayoutProps> = ({ children, title }) => (
|
||||
<div className="tw:pt-4">
|
||||
<SimpleCard className="tw:p-4 tw:w-full tw:lg:w-[65%] tw:m-auto">
|
||||
<div className="pt-4">
|
||||
<SimpleCard className="p-4 w-full lg:w-[65%] m-auto">
|
||||
<h2>{title}</h2>
|
||||
{children}
|
||||
</SimpleCard>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { faExternalLinkAlt, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Button, Card } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button, Card } from '@shlinkio/shlink-frontend-kit';
|
||||
import { clsx } from 'clsx';
|
||||
import { useEffect } from 'react';
|
||||
import { ExternalLink } from 'react-external-link';
|
||||
@@ -27,26 +27,26 @@ export const Home = ({ servers }: HomeProps) => {
|
||||
}, [serversList, navigate]);
|
||||
|
||||
return (
|
||||
<div className="tw:px-3 tw:w-full">
|
||||
<Card className="tw:mx-auto tw:max-w-[720px] tw:overflow-hidden">
|
||||
<div className="tw:flex tw:flex-col tw:md:flex-row">
|
||||
<div className="tw:p-6 tw:hidden tw:md:flex tw:items-center tw:w-[40%]">
|
||||
<div className="tw:w-full">
|
||||
<div className="px-3 w-full">
|
||||
<Card className="mx-auto max-w-[720px] overflow-hidden">
|
||||
<div className="flex flex-col md:flex-row">
|
||||
<div className="p-6 hidden md:flex items-center w-[40%]">
|
||||
<div className="w-full">
|
||||
<ShlinkLogo />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="tw:md:border-l tw:border-lm-border tw:dark:border-dm-border tw:flex-grow">
|
||||
<div className="md:border-l border-lm-border dark:border-dm-border flex-grow">
|
||||
<h1
|
||||
className={clsx(
|
||||
'tw:p-4 tw:text-center tw:border-lm-border tw:dark:border-dm-border',
|
||||
{ 'tw:border-b': !hasServers },
|
||||
'p-4 text-center border-lm-border dark:border-dm-border',
|
||||
{ 'border-b': !hasServers },
|
||||
)}
|
||||
>
|
||||
Welcome!
|
||||
</h1>
|
||||
{hasServers ? <ServersListGroup servers={serversList} /> : (
|
||||
<div className="tw:p-6 tw:text-center tw:flex tw:flex-col tw:gap-12 tw:text-xl">
|
||||
<div className="p-6 text-center flex flex-col gap-12 text-xl">
|
||||
<p>This application will help you manage your Shlink servers.</p>
|
||||
<p>
|
||||
<Button to="/server/create" size="lg" inline>
|
||||
@@ -56,7 +56,7 @@ export const Home = ({ servers }: HomeProps) => {
|
||||
<p>
|
||||
<ExternalLink href="https://shlink.io/documentation">
|
||||
<small>
|
||||
<span className="tw:mr-2">Learn more about Shlink</span>
|
||||
<span className="mr-2">Learn more about Shlink</span>
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} />
|
||||
</small>
|
||||
</ExternalLink>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { NavBar } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { NavBar } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { Link, useLocation } from 'react-router';
|
||||
import type { FCWithDeps } from '../container/utils';
|
||||
@@ -19,17 +19,17 @@ const MainHeader: FCWithDeps<unknown, MainHeaderDeps> = () => {
|
||||
|
||||
return (
|
||||
<NavBar
|
||||
className="tw:[&]:fixed tw:top-0 tw:z-900"
|
||||
className="[&]:fixed top-0 z-900"
|
||||
brand={(
|
||||
<Link to="/" className="tw:[&]:text-white tw:no-underline tw:flex tw:items-center tw:gap-2">
|
||||
<ShlinkLogo className="tw:w-7" color="white" /> <small className="tw:font-normal">Shlink</small>
|
||||
<Link to="/" className="[&]:text-white no-underline flex items-center gap-2">
|
||||
<ShlinkLogo className="w-7" color="white" /> <small className="font-normal">Shlink</small>
|
||||
</Link>
|
||||
)}
|
||||
>
|
||||
<NavBar.MenuItem
|
||||
to={settingsPath}
|
||||
active={pathname.startsWith(settingsPath)}
|
||||
className="tw:flex tw:items-center tw:gap-1.5"
|
||||
className="flex items-center gap-1.5"
|
||||
>
|
||||
<FontAwesomeIcon icon={cogsIcon} /> Settings
|
||||
</NavBar.MenuItem>
|
||||
|
||||
@@ -6,7 +6,7 @@ export type NoMenuLayoutProps = PropsWithChildren & {
|
||||
};
|
||||
|
||||
export const NoMenuLayout: FC<NoMenuLayoutProps> = ({ children, className }) => (
|
||||
<div className={clsx('tw:container tw:mx-auto tw:p-5 tw:pt-8 tw:max-md:p-3 tw:max-md:py-4', className)}>
|
||||
<div className={clsx('container mx-auto p-5 pt-8 max-md:p-3 max-md:py-4', className)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
import { ErrorLayout } from './ErrorLayout';
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface ShlinkVersionsProps {
|
||||
}
|
||||
|
||||
const VersionLink = ({ project, version }: { project: 'shlink' | 'shlink-web-client'; version: string }) => (
|
||||
<ExternalLink href={`https://github.com/shlinkio/${project}/releases/${version}`} className="tw:text-gray-500">
|
||||
<ExternalLink href={`https://github.com/shlinkio/${project}/releases/${version}`} className="text-gray-500">
|
||||
<b>{version}</b>
|
||||
</ExternalLink>
|
||||
);
|
||||
@@ -21,7 +21,7 @@ export const ShlinkVersions = ({ selectedServer, clientVersion = SHLINK_WEB_CLIE
|
||||
const normalizedClientVersion = normalizeVersion(clientVersion);
|
||||
|
||||
return (
|
||||
<small className="tw:text-gray-500">
|
||||
<small className="text-gray-500">
|
||||
{isReachableServer(selectedServer) && (
|
||||
<>Server: <VersionLink project="shlink" version={selectedServer.printableVersion} /> - </>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ export type ShlinkVersionsContainerProps = {
|
||||
|
||||
export const ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => (
|
||||
<div
|
||||
className={clsx('tw:text-center', { 'tw:md:ml-(--aside-menu-width)': isReachableServer(selectedServer) })}
|
||||
className={clsx('text-center', { 'md:ml-(--aside-menu-width)': isReachableServer(selectedServer) })}
|
||||
>
|
||||
<ShlinkVersions selectedServer={selectedServer} />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { MAIN_COLOR } from '@shlinkio/shlink-frontend-kit';
|
||||
import { brandColor } from '@shlinkio/shlink-frontend-kit';
|
||||
|
||||
export interface ShlinkLogoProps {
|
||||
color?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ShlinkLogo = ({ color = MAIN_COLOR, className }: ShlinkLogoProps) => (
|
||||
export const ShlinkLogo = ({ color = brandColor(), className }: ShlinkLogoProps) => (
|
||||
<svg className={className} viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill={color}>
|
||||
<path
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
@use '../node_modules/@shlinkio/shlink-frontend-kit/dist/base'; // Before bootstrap stylesheet
|
||||
@use '../node_modules/bootstrap/scss/bootstrap.scss' with (
|
||||
$primary: base.$mainColor // Override bootstrap's primary color
|
||||
);
|
||||
@use '../node_modules/@shlinkio/shlink-frontend-kit/dist/index'; // After bootstrap. Includes CSS overrides
|
||||
@use '../node_modules/@shlinkio/shlink-web-component/dist/index' as c-index;
|
||||
@@ -5,7 +5,6 @@ import pack from '../package.json';
|
||||
import { container } from './container';
|
||||
import { setUpStore } from './container/store';
|
||||
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
||||
import './index.scss';
|
||||
import './tailwind.css';
|
||||
|
||||
const store = setUpStore(container);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { TimeoutToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { ResultProps } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button, Result } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import type { ResultProps,TimeoutToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { Button, Result,useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
@@ -28,7 +26,7 @@ type CreateServerDeps = {
|
||||
};
|
||||
|
||||
const ImportResult = ({ variant }: Pick<ResultProps, 'variant'>) => (
|
||||
<div className="tw:mt-4">
|
||||
<div className="mt-4">
|
||||
<Result variant={variant}>
|
||||
{variant === 'success' && 'Servers properly imported. You can now select one from the list :)'}
|
||||
{variant === 'error' && 'The servers could not be imported. Make sure the format is correct.'}
|
||||
@@ -42,10 +40,10 @@ const CreateServer: FCWithDeps<CreateServerProps, CreateServerDeps> = ({ servers
|
||||
const goBack = useGoBack();
|
||||
const hasServers = !!Object.keys(servers).length;
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
const [serversImported, setServersImported] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME);
|
||||
const [serversImported, setServersImported] = useTimeoutToggle({ delay: SHOW_IMPORT_MSG_TIME });
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
const [errorImporting, setErrorImporting] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME);
|
||||
const [isConfirmModalOpen, toggleConfirmModal] = useToggle();
|
||||
const [errorImporting, setErrorImporting] = useTimeoutToggle({ delay: SHOW_IMPORT_MSG_TIME });
|
||||
const { flag: isConfirmModalOpen, toggle: toggleConfirmModal } = useToggle();
|
||||
const [serverData, setServerData] = useState<ServerData>();
|
||||
const saveNewServer = useCallback((newServerData: ServerData) => {
|
||||
const [newServerWithUniqueId] = ensureUniqueIds(servers, [newServerData]);
|
||||
|
||||
@@ -17,7 +17,7 @@ type DeleteServerButtonDeps = {
|
||||
|
||||
const DeleteServerButton: FCWithDeps<DeleteServerButtonProps, DeleteServerButtonDeps> = ({ server, children }) => {
|
||||
const { DeleteServerModal } = useDependencies(DeleteServerButton);
|
||||
const [isModalOpen, , showModal, hideModal] = useToggle();
|
||||
const { flag: isModalOpen, setToTrue: showModal, setToFalse: hideModal } = useToggle();
|
||||
const navigate = useNavigate();
|
||||
const onClose = useCallback((confirmed: boolean) => {
|
||||
hideModal();
|
||||
@@ -28,7 +28,7 @@ const DeleteServerButton: FCWithDeps<DeleteServerButtonProps, DeleteServerButton
|
||||
|
||||
return (
|
||||
<>
|
||||
<button type="button" className="tw:text-danger tw:hover:underline" onClick={showModal}>
|
||||
<button type="button" className="text-danger hover:underline" onClick={showModal}>
|
||||
{children}
|
||||
</button>
|
||||
<DeleteServerModal server={server} open={isModalOpen} onClose={onClose} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ExitAction } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { CardModal } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import type { ExitAction } from '@shlinkio/shlink-frontend-kit';
|
||||
import { CardModal } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import type { ServerWithId } from './data';
|
||||
@@ -31,7 +31,7 @@ export const DeleteServerModal: FC<DeleteServerModalConnectProps> = ({ server, o
|
||||
onClosed={onClosed}
|
||||
confirmText="Delete"
|
||||
>
|
||||
<div className="tw:flex tw:flex-col tw:gap-y-4">
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p>
|
||||
<p>
|
||||
<i>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useParsedQuery } from '@shlinkio/shlink-frontend-kit';
|
||||
import { Button } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button,useParsedQuery } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||
import type { FCWithDeps } from '../container/utils';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import type { TimeoutToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { Button, Result, SearchInput, SimpleCard, Table } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button, Result, SearchInput, SimpleCard, Table } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||
@@ -40,22 +40,22 @@ const ManageServers: FCWithDeps<ManageServersProps, ManageServersDeps> = ({ serv
|
||||
);
|
||||
const hasAutoConnect = allServers.some(({ autoConnect }) => !!autoConnect);
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
const [errorImporting, setErrorImporting] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME);
|
||||
const [errorImporting, setErrorImporting] = useTimeoutToggle({ delay: SHOW_IMPORT_MSG_TIME });
|
||||
|
||||
return (
|
||||
<NoMenuLayout className="tw:flex tw:flex-col tw:gap-y-4">
|
||||
<NoMenuLayout className="flex flex-col gap-y-4">
|
||||
<SearchInput onChange={setSearchTerm} />
|
||||
|
||||
<div className="tw:flex tw:flex-col tw:md:flex-row tw:gap-2">
|
||||
<div className="tw:flex tw:gap-2">
|
||||
<ImportServersBtn className="tw:flex-grow" onError={setErrorImporting}>Import servers</ImportServersBtn>
|
||||
<div className="flex flex-col md:flex-row gap-2">
|
||||
<div className="flex gap-2">
|
||||
<ImportServersBtn className="flex-grow" onError={setErrorImporting}>Import servers</ImportServersBtn>
|
||||
{filteredServers.length > 0 && (
|
||||
<Button variant="secondary" className="tw:flex-grow" onClick={async () => serversExporter.exportServers()}>
|
||||
<Button variant="secondary" className="flex-grow" onClick={async () => serversExporter.exportServers()}>
|
||||
<FontAwesomeIcon icon={exportIcon} /> Export servers
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<Button className="tw:md:ml-auto" to="/server/create">
|
||||
<Button className="md:ml-auto" to="/server/create">
|
||||
<FontAwesomeIcon icon={plusIcon} /> Add a server
|
||||
</Button>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@ const ManageServers: FCWithDeps<ManageServersProps, ManageServersDeps> = ({ serv
|
||||
<Table header={(
|
||||
<Table.Row>
|
||||
{hasAutoConnect && (
|
||||
<Table.Cell className="tw:w-[35px]"><span className="tw:sr-only">Auto-connect</span></Table.Cell>
|
||||
<Table.Cell className="w-[35px]"><span className="sr-only">Auto-connect</span></Table.Cell>
|
||||
)}
|
||||
<Table.Cell>Name</Table.Cell>
|
||||
<Table.Cell>Base URL</Table.Cell>
|
||||
@@ -72,7 +72,7 @@ const ManageServers: FCWithDeps<ManageServersProps, ManageServersDeps> = ({ serv
|
||||
</Table.Row>
|
||||
)}>
|
||||
{!filteredServers.length && (
|
||||
<Table.Row className="tw:text-center"><Table.Cell colSpan={4}>No servers found.</Table.Cell></Table.Row>
|
||||
<Table.Row className="text-center"><Table.Cell colSpan={4}>No servers found.</Table.Cell></Table.Row>
|
||||
)}
|
||||
{filteredServers.map((server) => (
|
||||
<ManageServersRow key={server.id} server={server} hasAutoConnect={hasAutoConnect} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { faCheck as checkIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Table, Tooltip, useTooltip } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Table, Tooltip, useTooltip } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import type { FCWithDeps } from '../container/utils';
|
||||
@@ -22,14 +22,14 @@ const ManageServersRow: FCWithDeps<ManageServersRowProps, ManageServersRowDeps>
|
||||
const { anchor, tooltip } = useTooltip();
|
||||
|
||||
return (
|
||||
<Table.Row className="tw:relative">
|
||||
<Table.Row className="relative">
|
||||
{hasAutoConnect && (
|
||||
<Table.Cell columnName="Auto-connect">
|
||||
{server.autoConnect && (
|
||||
<>
|
||||
<FontAwesomeIcon
|
||||
icon={checkIcon}
|
||||
className="tw:text-lm-brand tw:dark:text-dm-brand"
|
||||
className="text-lm-brand dark:text-dm-brand"
|
||||
{...anchor}
|
||||
/>
|
||||
<Tooltip {...tooltip}>Auto-connect to this server</Tooltip>
|
||||
@@ -37,11 +37,11 @@ const ManageServersRow: FCWithDeps<ManageServersRowProps, ManageServersRowDeps>
|
||||
)}
|
||||
</Table.Cell>
|
||||
)}
|
||||
<Table.Cell className="tw:font-bold" columnName="Name">
|
||||
<Table.Cell className="font-bold" columnName="Name">
|
||||
<Link to={`/server/${server.id}`}>{server.name}</Link>
|
||||
</Table.Cell>
|
||||
<Table.Cell columnName="Base URL" className="tw:max-lg:border-b-0">{server.url}</Table.Cell>
|
||||
<Table.Cell className="tw:text-right tw:max-lg:absolute tw:right-0 tw:-top-1 tw:mx-lg:pt-0">
|
||||
<Table.Cell columnName="Base URL" className="max-lg:border-b-0">{server.url}</Table.Cell>
|
||||
<Table.Cell className="text-right max-lg:absolute right-0 -top-1 mx-lg:pt-0">
|
||||
<ManageServersRowDropdown server={server} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
faPlug as connectIcon,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { RowDropdown } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { RowDropdown,useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import type { FCWithDeps } from '../container/utils';
|
||||
import { componentFactory, useDependencies } from '../container/utils';
|
||||
@@ -30,7 +29,7 @@ const ManageServersRowDropdown: FCWithDeps<ManageServersRowDropdownConnectProps,
|
||||
{ server, setAutoConnect },
|
||||
) => {
|
||||
const { DeleteServerModal } = useDependencies(ManageServersRowDropdown);
|
||||
const { flag: isModalOpen, setToTrue: showModal, setToFalse: hideModal } = useToggle(false, true);
|
||||
const { flag: isModalOpen, setToTrue: showModal, setToFalse: hideModal } = useToggle();
|
||||
const serverUrl = `/server/${server.id}`;
|
||||
const { autoConnect: isAutoConnect } = server;
|
||||
const autoConnectIcon = isAutoConnect ? toggleOffIcon : toggleOnIcon;
|
||||
@@ -38,17 +37,17 @@ const ManageServersRowDropdown: FCWithDeps<ManageServersRowDropdownConnectProps,
|
||||
return (
|
||||
<>
|
||||
<RowDropdown menuAlignment="right">
|
||||
<RowDropdown.Item to={serverUrl} className="tw:gap-1.5">
|
||||
<RowDropdown.Item to={serverUrl} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={connectIcon} fixedWidth /> Connect
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Item to={`${serverUrl}/edit`} className="tw:gap-1.5">
|
||||
<RowDropdown.Item to={`${serverUrl}/edit`} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit server
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Item onClick={() => setAutoConnect(server, !isAutoConnect)} className="tw:gap-1.5">
|
||||
<RowDropdown.Item onClick={() => setAutoConnect(server, !isAutoConnect)} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Separator />
|
||||
<RowDropdown.Item className="tw:[&]:text-danger tw:gap-1.5" onClick={showModal}>
|
||||
<RowDropdown.Item className="[&]:text-danger gap-1.5" onClick={showModal}>
|
||||
<FontAwesomeIcon icon={deleteIcon} fixedWidth /> Remove server
|
||||
</RowDropdown.Item>
|
||||
</RowDropdown>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { faPlus as plusIcon, faServer as serverIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Dropdown, NavBar } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Dropdown, NavBar } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { SelectedServer, ServersMap } from './data';
|
||||
import { getServerId } from './data';
|
||||
|
||||
@@ -14,7 +14,7 @@ export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProp
|
||||
|
||||
return (
|
||||
<NavBar.Dropdown buttonContent={(
|
||||
<span className="tw:flex tw:items-center tw:gap-1.5">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<FontAwesomeIcon icon={serverIcon} fixedWidth /> Servers
|
||||
</span>
|
||||
)}>
|
||||
|
||||
@@ -15,12 +15,12 @@ const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
||||
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',
|
||||
'flex items-center justify-between gap-x-2 px-4 py-3',
|
||||
'rounded-none hover:bg-lm-secondary hover:dark:bg-dm-secondary',
|
||||
'border-b last:border-0 border-lm-border dark:border-dm-border',
|
||||
)}
|
||||
>
|
||||
<span className="tw:truncate">{name}</span>
|
||||
<span className="truncate">{name}</span>
|
||||
<FontAwesomeIcon icon={chevronIcon} />
|
||||
</Link>
|
||||
);
|
||||
@@ -31,9 +31,9 @@ export const ServersListGroup: FC<ServersListGroupProps> = ({ servers, borderles
|
||||
<div
|
||||
data-testid="list"
|
||||
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 },
|
||||
'w-full border-lm-border dark:border-dm-border',
|
||||
'md:max-h-56 md:overflow-y-auto -mb-1 scroll-thin',
|
||||
{ 'border-y': !borderless },
|
||||
)}
|
||||
>
|
||||
{servers.map(({ id, name }) => <ServerListItem key={id} id={id} name={name} />)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CardModal } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { CardModal } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { Fragment } from 'react';
|
||||
import type { ServerData } from '../data';
|
||||
@@ -26,7 +26,7 @@ export const DuplicatedServersModal: FC<DuplicatedServersModalProps> = (
|
||||
cancelText={hasMultipleServers ? 'Ignore duplicates' : 'Discard'}
|
||||
>
|
||||
<p>{hasMultipleServers ? 'The next servers already exist:' : 'There is already a server with:'}</p>
|
||||
<ul className="tw:list-disc tw:mt-4">
|
||||
<ul className="list-disc mt-4">
|
||||
{duplicatedServers.map(({ url, apiKey }, index) => (!hasMultipleServers ? (
|
||||
<Fragment key={index}>
|
||||
<li>URL: <b>{url}</b></li>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import { Button, Tooltip, useTooltip } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Button, Tooltip, useToggle , useTooltip } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { ChangeEvent, PropsWithChildren } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import type { FCWithDeps } from '../../container/utils';
|
||||
@@ -40,7 +39,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { anchor, tooltip } = useTooltip({ placement: tooltipPlacement });
|
||||
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
||||
const { flag: isModalOpen, setToTrue: showModal, setToFalse: hideModal } = useToggle(false, true);
|
||||
const { flag: isModalOpen, setToTrue: showModal, setToFalse: hideModal } = useToggle();
|
||||
const newServersCreatedRef = useRef(false);
|
||||
|
||||
const onFile = useCallback(
|
||||
@@ -94,7 +93,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
||||
<input
|
||||
type="file"
|
||||
accept=".csv"
|
||||
className="tw:hidden"
|
||||
className="hidden"
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
ref={fileInputRef}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Message } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Card, Message } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
||||
@@ -23,8 +23,8 @@ const ServerError: FCWithDeps<ServerErrorProps, ServerErrorDeps> = ({ servers, s
|
||||
|
||||
return (
|
||||
<NoMenuLayout>
|
||||
<div className="tw:flex tw:flex-col tw:items-center tw:gap-y-4 tw:md:gap-y-8">
|
||||
<Message className="tw:w-full tw:lg:w-[80%]" variant="error">
|
||||
<div className="flex flex-col items-center gap-y-4 md:gap-y-8">
|
||||
<Message className="w-full lg:w-[80%]" variant="error">
|
||||
{!isServerWithId(selectedServer) && 'Could not find this Shlink server.'}
|
||||
{isServerWithId(selectedServer) && (
|
||||
<>
|
||||
@@ -34,16 +34,16 @@ const ServerError: FCWithDeps<ServerErrorProps, ServerErrorDeps> = ({ servers, s
|
||||
)}
|
||||
</Message>
|
||||
|
||||
<p className="tw:text-xl">
|
||||
<p className="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">
|
||||
<Card className="w-full max-w-100 overflow-hidden">
|
||||
<ServersListGroup borderless servers={Object.values(servers)} />
|
||||
</Card>
|
||||
|
||||
{isServerWithId(selectedServer) && (
|
||||
<p className="tw:text-xl">
|
||||
<p className="text-xl">
|
||||
Alternatively, if you think you may have misconfigured this server, you
|
||||
can <DeleteServerButton server={selectedServer}>remove
|
||||
it</DeleteServerButton> or
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||
import {
|
||||
Checkbox,
|
||||
import { Checkbox,
|
||||
Details,
|
||||
Label,
|
||||
LabelledInput,
|
||||
LabelledRevealablePasswordInput,
|
||||
SimpleCard,
|
||||
} from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
useToggle ,
|
||||
} from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { usePreventDefault } from '../../utils/utils';
|
||||
@@ -24,13 +23,12 @@ export const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, child
|
||||
const [apiKey, setApiKey] = useState(initialValues?.apiKey ?? '');
|
||||
const { flag: forwardCredentials, toggle: toggleForwardCredentials } = useToggle(
|
||||
initialValues?.forwardCredentials ?? false,
|
||||
true,
|
||||
);
|
||||
const handleSubmit = usePreventDefault(() => onSubmit({ name, url, apiKey, forwardCredentials }));
|
||||
|
||||
return (
|
||||
<form name="serverForm" onSubmit={handleSubmit}>
|
||||
<SimpleCard className="tw:mb-4" bodyClassName="tw:flex tw:flex-col tw:gap-y-3" title={title}>
|
||||
<SimpleCard className="mb-4" bodyClassName="flex flex-col gap-y-3" title={title}>
|
||||
<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 />
|
||||
<LabelledRevealablePasswordInput
|
||||
@@ -40,25 +38,25 @@ export const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, child
|
||||
required
|
||||
/>
|
||||
<Details summary="Advanced options">
|
||||
<div className="tw:flex tw:flex-col tw:gap-0.5">
|
||||
<Label className="tw:flex tw:items-center tw:gap-x-1.5 tw:cursor-pointer">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<Label className="flex items-center gap-x-1.5 cursor-pointer">
|
||||
<Checkbox onChange={toggleForwardCredentials} checked={forwardCredentials} />
|
||||
Forward credentials to this server on every request.
|
||||
</Label>
|
||||
<small className="tw:pl-5.5 tw:text-gray-600 tw:dark:text-gray-400 tw:mt-0.5">
|
||||
<small className="pl-5.5 text-gray-600 dark:text-gray-400 mt-0.5">
|
||||
{'"'}Credentials{'"'} here means cookies, TLS client certificates, or authentication headers containing a username
|
||||
and password.
|
||||
</small>
|
||||
<small className="tw:pl-5.5 tw:text-gray-600 tw:dark:text-gray-400">
|
||||
<small className="pl-5.5 text-gray-600 dark:text-gray-400">
|
||||
<b>Important!</b> If you are not sure what this means, leave it unchecked. Enabling this option will
|
||||
make all requests fail for Shlink older than v4.5.0, as it requires the server to set a more strict
|
||||
value for <code className="tw:whitespace-nowrap">Access-Control-Allow-Origin</code> than <code>*</code>.
|
||||
value for <code className="whitespace-nowrap">Access-Control-Allow-Origin</code> than <code>*</code>.
|
||||
</small>
|
||||
</div>
|
||||
</Details>
|
||||
</SimpleCard>
|
||||
|
||||
<div className="tw:flex tw:items-center tw:justify-end tw:gap-x-2">{children}</div>
|
||||
<div className="flex items-center justify-end gap-x-2">{children}</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Message } from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||
import { Message } from '@shlinkio/shlink-frontend-kit';
|
||||
import type { FC } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import 'tailwindcss' prefix(tw) important;
|
||||
@import 'tailwindcss';
|
||||
@import '@shlinkio/shlink-frontend-kit/tailwind.preset.css';
|
||||
@import '@shlinkio/shlink-web-component/tailwind.preset.css';
|
||||
@source '../node_modules/@shlinkio/shlink-frontend-kit';
|
||||
@@ -8,7 +8,7 @@
|
||||
:root {
|
||||
--footer-height: 2.3rem;
|
||||
--footer-margin: .8rem;
|
||||
/* Temp alias fo header-height to tw-header-height, so that shlink-web-component uses the right value */
|
||||
--header-height: var(--tw-header-height);
|
||||
/* FIXME Remove this once updated to shlink-web-component 0.15.1 */
|
||||
--header-height: 52px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user