mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Create component to display input with an icon
This commit is contained in:
parent
006e6b30b7
commit
bace2a10e8
5 changed files with 139 additions and 52 deletions
86
package-lock.json
generated
86
package-lock.json
generated
|
@ -10,10 +10,11 @@
|
||||||
"@babel/preset-env": "^7.20.2",
|
"@babel/preset-env": "^7.20.2",
|
||||||
"@babel/preset-react": "^7.18.6",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
"@fortawesome/fontawesome-free": "^6.3.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
"@fortawesome/fontawesome-svg-core": "^6.3.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.2.1",
|
"@fortawesome/free-brands-svg-icons": "^6.3.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
"@fortawesome/free-regular-svg-icons": "^6.3.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.3.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@json2csv/plainjs": "^6.1.2",
|
"@json2csv/plainjs": "^6.1.2",
|
||||||
"@reduxjs/toolkit": "^1.9.1",
|
"@reduxjs/toolkit": "^1.9.1",
|
||||||
|
@ -1937,49 +1938,66 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/fontawesome-free": {
|
"node_modules/@fortawesome/fontawesome-free": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "(CC-BY-4.0 AND MIT)",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "(CC-BY-4.0 AND MIT)",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
@ -13611,27 +13629,45 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-common-types": {
|
"@fortawesome/fontawesome-common-types": {
|
||||||
"version": "6.2.1"
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg=="
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-free": {
|
"@fortawesome/fontawesome-free": {
|
||||||
"version": "6.2.1"
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA=="
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-svg-core": {
|
"@fortawesome/fontawesome-svg-core": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fortawesome/free-brands-svg-icons": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==",
|
||||||
|
"requires": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-regular-svg-icons": {
|
"@fortawesome/free-regular-svg-icons": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-solid-svg-icons": {
|
"@fortawesome/free-solid-svg-icons": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.2.1"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/react-fontawesome": {
|
"@fortawesome/react-fontawesome": {
|
||||||
|
|
|
@ -26,10 +26,11 @@
|
||||||
"@babel/preset-env": "^7.20.2",
|
"@babel/preset-env": "^7.20.2",
|
||||||
"@babel/preset-react": "^7.18.6",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
"@fortawesome/fontawesome-free": "^6.3.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
"@fortawesome/fontawesome-svg-core": "^6.3.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.2.1",
|
"@fortawesome/free-brands-svg-icons": "^6.3.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
"@fortawesome/free-regular-svg-icons": "^6.3.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.3.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@json2csv/plainjs": "^6.1.2",
|
"@json2csv/plainjs": "^6.1.2",
|
||||||
"@reduxjs/toolkit": "^1.9.1",
|
"@reduxjs/toolkit": "^1.9.1",
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type { IconProp } from '@fortawesome/fontawesome-svg-core';
|
import type { IconProp } from '@fortawesome/fontawesome-svg-core';
|
||||||
import { faAppleAlt, faDesktop, faMobileAndroidAlt } from '@fortawesome/free-solid-svg-icons';
|
import { faAndroid, faApple } from '@fortawesome/free-brands-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { faDesktop } from '@fortawesome/free-solid-svg-icons';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { parseISO } from 'date-fns';
|
import { parseISO } from 'date-fns';
|
||||||
import { isEmpty, pipe, replace, trim } from 'ramda';
|
import { isEmpty, pipe, replace, trim } from 'ramda';
|
||||||
import type { ChangeEvent, FC } from 'react';
|
import type { ChangeEvent, FC } from 'react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Button, FormGroup, Input, InputGroup, InputGroupText, Row } from 'reactstrap';
|
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
||||||
import type { InputType } from 'reactstrap/types/lib/Input';
|
import type { InputType } from 'reactstrap/types/lib/Input';
|
||||||
import type { DomainSelectorProps } from '../domains/DomainSelector';
|
import type { DomainSelectorProps } from '../domains/DomainSelector';
|
||||||
import type { SelectedServer } from '../servers/data';
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
@ -16,6 +16,7 @@ import type { DateTimeInputProps } from '../utils/dates/DateTimeInput';
|
||||||
import { DateTimeInput } from '../utils/dates/DateTimeInput';
|
import { DateTimeInput } from '../utils/dates/DateTimeInput';
|
||||||
import { formatIsoDate } from '../utils/helpers/date';
|
import { formatIsoDate } from '../utils/helpers/date';
|
||||||
import { useFeature } from '../utils/helpers/features';
|
import { useFeature } from '../utils/helpers/features';
|
||||||
|
import { IconInput } from '../utils/IconInput';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import { handleEventPreventingDefault, hasValue } from '../utils/utils';
|
import { handleEventPreventingDefault, hasValue } from '../utils/utils';
|
||||||
import type { DeviceLongUrls, ShortUrlData } from './data';
|
import type { DeviceLongUrls, ShortUrlData } from './data';
|
||||||
|
@ -90,11 +91,8 @@ export const ShortUrlForm = (
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
const renderDeviceLongUrlInput = (id: keyof DeviceLongUrls, placeholder: string, icon: IconProp) => (
|
const renderDeviceLongUrlInput = (id: keyof DeviceLongUrls, placeholder: string, icon: IconProp) => (
|
||||||
<InputGroup>
|
<IconInput
|
||||||
<InputGroupText>
|
icon={icon}
|
||||||
<FontAwesomeIcon icon={icon} fixedWidth />
|
|
||||||
</InputGroupText>
|
|
||||||
<Input
|
|
||||||
id={id}
|
id={id}
|
||||||
type="url"
|
type="url"
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
|
@ -107,7 +105,6 @@ export const ShortUrlForm = (
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
|
||||||
);
|
);
|
||||||
const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateTimeInputProps> = {}) => (
|
const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateTimeInputProps> = {}) => (
|
||||||
<DateTimeInput
|
<DateTimeInput
|
||||||
|
@ -158,10 +155,10 @@ export const ShortUrlForm = (
|
||||||
<div className="col-sm-6 mb-3">
|
<div className="col-sm-6 mb-3">
|
||||||
<SimpleCard title="Device-specific long URLs">
|
<SimpleCard title="Device-specific long URLs">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
{renderDeviceLongUrlInput('android', 'Android-specific redirection', faMobileAndroidAlt)}
|
{renderDeviceLongUrlInput('android', 'Android-specific redirection', faAndroid)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
{renderDeviceLongUrlInput('ios', 'iOS-specific redirection', faAppleAlt)}
|
{renderDeviceLongUrlInput('ios', 'iOS-specific redirection', faApple)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
{renderDeviceLongUrlInput('desktop', 'Desktop-specific redirection', faDesktop)}
|
{renderDeviceLongUrlInput('desktop', 'Desktop-specific redirection', faDesktop)}
|
||||||
</SimpleCard>
|
</SimpleCard>
|
||||||
|
|
26
src/utils/IconInput.scss
Normal file
26
src/utils/IconInput.scss
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
@import './mixins/vertical-align';
|
||||||
|
@import './base';
|
||||||
|
|
||||||
|
.icon-input-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input-container__input {
|
||||||
|
padding-right: 35px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input-container__input:not(:disabled) {
|
||||||
|
background-color: var(--primary-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .icon-input-container__input:not(:disabled),
|
||||||
|
.dropdown .icon-input-container__input:not(:disabled) {
|
||||||
|
background-color: var(--input-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input-container__icon {
|
||||||
|
@include vertical-align();
|
||||||
|
|
||||||
|
right: .75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
27
src/utils/IconInput.tsx
Normal file
27
src/utils/IconInput.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import type { IconProp } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import type { InputProps } from 'reactstrap';
|
||||||
|
import { Input } from 'reactstrap';
|
||||||
|
import './IconInput.scss';
|
||||||
|
|
||||||
|
type IconInputProps = InputProps & { icon: IconProp };
|
||||||
|
|
||||||
|
export const IconInput: FC<IconInputProps> = ({ icon, className, ...rest }) => {
|
||||||
|
const ref = useRef<{ input: HTMLInputElement }>();
|
||||||
|
const classes = classNames('icon-input-container__input', className);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="icon-input-container">
|
||||||
|
<Input className={classes} {...rest} />
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={icon}
|
||||||
|
fixedWidth
|
||||||
|
className="icon-input-container__icon"
|
||||||
|
onClick={() => ref.current?.input.focus()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in a new issue