From bace2a10e85064b0270e44a5aa24ece29dec63c7 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 13 Mar 2023 18:01:21 +0100 Subject: [PATCH] Create component to display input with an icon --- package-lock.json | 86 +++++++++++++++++++++++---------- package.json | 9 ++-- src/short-urls/ShortUrlForm.tsx | 43 ++++++++--------- src/utils/IconInput.scss | 26 ++++++++++ src/utils/IconInput.tsx | 27 +++++++++++ 5 files changed, 139 insertions(+), 52 deletions(-) create mode 100644 src/utils/IconInput.scss create mode 100644 src/utils/IconInput.tsx diff --git a/package-lock.json b/package-lock.json index 81c020a6..0dd5c8b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,11 @@ "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", - "@fortawesome/fontawesome-free": "^6.2.1", - "@fortawesome/fontawesome-svg-core": "^6.2.1", - "@fortawesome/free-regular-svg-icons": "^6.2.1", - "@fortawesome/free-solid-svg-icons": "^6.2.1", + "@fortawesome/fontawesome-free": "^6.3.0", + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-brands-svg-icons": "^6.3.0", + "@fortawesome/free-regular-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", "@fortawesome/react-fontawesome": "^0.2.0", "@json2csv/plainjs": "^6.1.2", "@reduxjs/toolkit": "^1.9.1", @@ -1937,49 +1938,66 @@ } }, "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, - "license": "MIT", "engines": { "node": ">=6" } }, "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, - "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "engines": { "node": ">=6" } }, "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, - "license": "MIT", "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": { "node": ">=6" } }, "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, - "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" }, "engines": { "node": ">=6" } }, "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, - "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" }, "engines": { "node": ">=6" @@ -13611,27 +13629,45 @@ "dev": true }, "@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": { - "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": { - "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": { - "@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": { - "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": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" } }, "@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": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" } }, "@fortawesome/react-fontawesome": { diff --git a/package.json b/package.json index 4b2dd124..95f1d9f2 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,11 @@ "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", - "@fortawesome/fontawesome-free": "^6.2.1", - "@fortawesome/fontawesome-svg-core": "^6.2.1", - "@fortawesome/free-regular-svg-icons": "^6.2.1", - "@fortawesome/free-solid-svg-icons": "^6.2.1", + "@fortawesome/fontawesome-free": "^6.3.0", + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-brands-svg-icons": "^6.3.0", + "@fortawesome/free-regular-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", "@fortawesome/react-fontawesome": "^0.2.0", "@json2csv/plainjs": "^6.1.2", "@reduxjs/toolkit": "^1.9.1", diff --git a/src/short-urls/ShortUrlForm.tsx b/src/short-urls/ShortUrlForm.tsx index a893f9c0..68788064 100644 --- a/src/short-urls/ShortUrlForm.tsx +++ b/src/short-urls/ShortUrlForm.tsx @@ -1,12 +1,12 @@ import type { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { faAppleAlt, faDesktop, faMobileAndroidAlt } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faAndroid, faApple } from '@fortawesome/free-brands-svg-icons'; +import { faDesktop } from '@fortawesome/free-solid-svg-icons'; import classNames from 'classnames'; import { parseISO } from 'date-fns'; import { isEmpty, pipe, replace, trim } from 'ramda'; import type { ChangeEvent, FC } 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 { DomainSelectorProps } from '../domains/DomainSelector'; import type { SelectedServer } from '../servers/data'; @@ -16,6 +16,7 @@ import type { DateTimeInputProps } from '../utils/dates/DateTimeInput'; import { DateTimeInput } from '../utils/dates/DateTimeInput'; import { formatIsoDate } from '../utils/helpers/date'; import { useFeature } from '../utils/helpers/features'; +import { IconInput } from '../utils/IconInput'; import { SimpleCard } from '../utils/SimpleCard'; import { handleEventPreventingDefault, hasValue } from '../utils/utils'; import type { DeviceLongUrls, ShortUrlData } from './data'; @@ -90,24 +91,20 @@ export const ShortUrlForm = ( ); const renderDeviceLongUrlInput = (id: keyof DeviceLongUrls, placeholder: string, icon: IconProp) => ( - - - - - setShortUrlData({ - ...shortUrlData, - deviceLongUrls: { - ...(shortUrlData.deviceLongUrls ?? {}), - [id]: setResettableValue(e.target.value, initialState.deviceLongUrls?.[id]), - }, - })} - /> - + setShortUrlData({ + ...shortUrlData, + deviceLongUrls: { + ...(shortUrlData.deviceLongUrls ?? {}), + [id]: setResettableValue(e.target.value, initialState.deviceLongUrls?.[id]), + }, + })} + /> ); const renderDateInput = (id: DateFields, placeholder: string, props: Partial = {}) => ( - {renderDeviceLongUrlInput('android', 'Android-specific redirection', faMobileAndroidAlt)} + {renderDeviceLongUrlInput('android', 'Android-specific redirection', faAndroid)} - {renderDeviceLongUrlInput('ios', 'iOS-specific redirection', faAppleAlt)} + {renderDeviceLongUrlInput('ios', 'iOS-specific redirection', faApple)} {renderDeviceLongUrlInput('desktop', 'Desktop-specific redirection', faDesktop)} diff --git a/src/utils/IconInput.scss b/src/utils/IconInput.scss new file mode 100644 index 00000000..3e3e6d04 --- /dev/null +++ b/src/utils/IconInput.scss @@ -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; +} diff --git a/src/utils/IconInput.tsx b/src/utils/IconInput.tsx new file mode 100644 index 00000000..7afe0416 --- /dev/null +++ b/src/utils/IconInput.tsx @@ -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 = ({ icon, className, ...rest }) => { + const ref = useRef<{ input: HTMLInputElement }>(); + const classes = classNames('icon-input-container__input', className); + + return ( +
+ + ref.current?.input.focus()} + /> +
+ ); +};