feat: update input/button style + add react-toggle

This commit is contained in:
Sonny
2023-12-07 17:49:47 +01:00
parent 6f04435d53
commit 406bf281b0
9 changed files with 199 additions and 25 deletions

28
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"@ducanh2912/next-pwa": "^9.7.2", "@ducanh2912/next-pwa": "^9.7.2",
"@prisma/client": "^5.6.0", "@prisma/client": "^5.6.0",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@types/react-toggle": "^4.0.5",
"accept-language": "^3.0.18", "accept-language": "^3.0.18",
"axios": "^1.6.2", "axios": "^1.6.2",
"clsx": "^2.0.0", "clsx": "^2.0.0",
@@ -28,6 +29,7 @@
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-select": "^5.8.0", "react-select": "^5.8.0",
"react-tabs": "^6.0.2", "react-tabs": "^6.0.2",
"react-toggle": "^4.1.3",
"sass": "^1.69.5", "sass": "^1.69.5",
"sharp": "^0.32.6", "sharp": "^0.32.6",
"yup": "^1.3.2" "yup": "^1.3.2"
@@ -2815,6 +2817,14 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/react-toggle": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/react-toggle/-/react-toggle-4.0.5.tgz",
"integrity": "sha512-MHHEDe7GnF/EhLtI5sT70Dqab8rwlgjRZtu/u6gmfbYd+HeYxWiUSRog16+1BCfkz7Wy2VU6+TPU2oCsDtqDzA==",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-transition-group": { "node_modules/@types/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -3909,6 +3919,11 @@
"node": ">=6.0" "node": ">=6.0"
} }
}, },
"node_modules/classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
},
"node_modules/clean-webpack-plugin": { "node_modules/clean-webpack-plugin": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz",
@@ -7955,6 +7970,19 @@
"react": "^18.0.0" "react": "^18.0.0"
} }
}, },
"node_modules/react-toggle": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.1.3.tgz",
"integrity": "sha512-WoPrvbwfQSvoagbrDnXPrlsxwzuhQIrs+V0I162j/s+4XPgY/YDAUmHSeWiroznfI73wj+MBydvW95zX8ABbSg==",
"dependencies": {
"classnames": "^2.2.5"
},
"peerDependencies": {
"prop-types": ">= 15.3.0 < 19",
"react": ">= 15.3.0 < 19",
"react-dom": ">= 15.3.0 < 19"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",

View File

@@ -14,6 +14,7 @@
"@ducanh2912/next-pwa": "^9.7.2", "@ducanh2912/next-pwa": "^9.7.2",
"@prisma/client": "^5.6.0", "@prisma/client": "^5.6.0",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@types/react-toggle": "^4.0.5",
"accept-language": "^3.0.18", "accept-language": "^3.0.18",
"axios": "^1.6.2", "axios": "^1.6.2",
"clsx": "^2.0.0", "clsx": "^2.0.0",
@@ -33,6 +34,7 @@
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-select": "^5.8.0", "react-select": "^5.8.0",
"react-tabs": "^6.0.2", "react-tabs": "^6.0.2",
"react-toggle": "^4.1.3",
"sass": "^1.69.5", "sass": "^1.69.5",
"sharp": "^0.32.6", "sharp": "^0.32.6",
"yup": "^1.3.2" "yup": "^1.3.2"

View File

@@ -1,4 +1,5 @@
import { MutableRefObject, useState } from 'react'; import { MutableRefObject, useState } from 'react';
import Toggle from 'react-toggle';
interface SelectorProps { interface SelectorProps {
name: string; name: string;
@@ -22,7 +23,7 @@ export default function Checkbox({
placeholder = 'Type something...', placeholder = 'Type something...',
isChecked, isChecked,
onChangeCallback, onChangeCallback,
}: SelectorProps): JSX.Element { }: Readonly<SelectorProps>): JSX.Element {
const [checkboxValue, setCheckboxValue] = useState<boolean>(isChecked); const [checkboxValue, setCheckboxValue] = useState<boolean>(isChecked);
function onChange({ target }) { function onChange({ target }) {
@@ -50,13 +51,11 @@ export default function Checkbox({
{labelComponent} {labelComponent}
</label> </label>
)} )}
<input <Toggle
type='checkbox'
id={name}
name={name}
onChange={onChange} onChange={onChange}
checked={checkboxValue} checked={checkboxValue}
placeholder={placeholder} id={name}
name={name}
ref={innerRef} ref={innerRef}
disabled={disabled} disabled={disabled}
/> />

View File

@@ -15,9 +15,9 @@ import { makeRequest } from 'lib/request';
export default function PageRemoveCategory({ export default function PageRemoveCategory({
category, category,
}: { }: Readonly<{
category: Category; category: Category;
}) { }>) {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const router = useRouter(); const router = useRouter();

View File

@@ -7,20 +7,20 @@ import PATHS from 'constants/paths';
import useAutoFocus from 'hooks/useAutoFocus'; import useAutoFocus from 'hooks/useAutoFocus';
import { getServerSideTranslation } from 'i18n'; import { getServerSideTranslation } from 'i18n';
import getUserCategories from 'lib/category/getUserCategories'; import getUserCategories from 'lib/category/getUserCategories';
import { makeRequest } from 'lib/request';
import { isValidHttpUrl } from 'lib/url';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormEvent, useMemo, useState } from 'react'; import { FormEvent, useMemo, useState } from 'react';
import styles from 'styles/form.module.scss'; import styles from 'styles/form.module.scss';
import { Category, Link } from 'types'; import { Category, Link } from 'types';
import { withAuthentication } from 'utils/session'; import { withAuthentication } from 'utils/session';
import { makeRequest } from 'lib/request';
import { isValidHttpUrl } from 'lib/url';
export default function PageCreateLink({ export default function PageCreateLink({
categories, categories,
}: { }: Readonly<{
categories: Category[]; categories: Category[];
}) { }>) {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const autoFocusRef = useAutoFocus(); const autoFocusRef = useAutoFocus();

View File

@@ -8,22 +8,22 @@ import useAutoFocus from 'hooks/useAutoFocus';
import { getServerSideTranslation } from 'i18n'; import { getServerSideTranslation } from 'i18n';
import getUserCategories from 'lib/category/getUserCategories'; import getUserCategories from 'lib/category/getUserCategories';
import getUserLink from 'lib/link/getUserLink'; import getUserLink from 'lib/link/getUserLink';
import { makeRequest } from 'lib/request';
import { isValidHttpUrl } from 'lib/url';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormEvent, useMemo, useState } from 'react'; import { FormEvent, useMemo, useState } from 'react';
import styles from 'styles/form.module.scss'; import styles from 'styles/form.module.scss';
import { Category, Link } from 'types'; import { Category, Link } from 'types';
import { isValidHttpUrl } from 'lib/url';
import { withAuthentication } from 'utils/session'; import { withAuthentication } from 'utils/session';
import { makeRequest } from 'lib/request';
export default function PageEditLink({ export default function PageEditLink({
link, link,
categories, categories,
}: { }: Readonly<{
link: Link; link: Link;
categories: Category[]; categories: Category[];
}) { }>) {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const autoFocusRef = useAutoFocus(); const autoFocusRef = useAutoFocus();

View File

@@ -5,15 +5,15 @@ import TextBox from 'components/TextBox';
import PATHS from 'constants/paths'; import PATHS from 'constants/paths';
import { getServerSideTranslation } from 'i18n'; import { getServerSideTranslation } from 'i18n';
import getUserLink from 'lib/link/getUserLink'; import getUserLink from 'lib/link/getUserLink';
import { makeRequest } from 'lib/request';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormEvent, useMemo, useState } from 'react'; import { FormEvent, useMemo, useState } from 'react';
import styles from 'styles/form.module.scss'; import styles from 'styles/form.module.scss';
import { Link } from 'types'; import { Link } from 'types';
import { withAuthentication } from 'utils/session'; import { withAuthentication } from 'utils/session';
import { makeRequest } from 'lib/request';
export default function PageRemoveLink({ link }: { link: Link }) { export default function PageRemoveLink({ link }: Readonly<{ link: Link }>) {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();

143
src/styles/checkbox.scss Normal file
View File

@@ -0,0 +1,143 @@
@import 'colors.scss';
.react-toggle {
touch-action: pan-x;
display: inline-block;
position: relative;
cursor: pointer;
background-color: transparent;
border: 0;
padding: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent;
}
.react-toggle-screenreader-only {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.react-toggle--disabled {
cursor: not-allowed;
opacity: 0.5;
-webkit-transition: opacity 0.25s;
transition: opacity 0.25s;
}
.react-toggle-track {
width: 50px;
height: 24px;
padding: 0;
border-radius: 30px;
background-color: #4d4d4d;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
transition: all 0.2s ease;
}
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
background-color: #000000;
}
.react-toggle--checked .react-toggle-track {
background-color: $blue;
}
.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
background-color: $dark-blue;
}
.react-toggle-track-check {
position: absolute;
width: 14px;
height: 10px;
top: 0px;
bottom: 0px;
margin-top: auto;
margin-bottom: auto;
line-height: 0;
left: 8px;
opacity: 0;
-webkit-transition: opacity 0.25s ease;
-moz-transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
}
.react-toggle--checked .react-toggle-track-check {
opacity: 1;
-webkit-transition: opacity 0.25s ease;
-moz-transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
}
.react-toggle-track-x {
position: absolute;
width: 10px;
height: 10px;
top: 0px;
bottom: 0px;
margin-top: auto;
margin-bottom: auto;
line-height: 0;
right: 10px;
opacity: 1;
-webkit-transition: opacity 0.25s ease;
-moz-transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
}
.react-toggle--checked .react-toggle-track-x {
opacity: 0;
}
.react-toggle-thumb {
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
position: absolute;
top: 1px;
left: 1px;
width: 22px;
height: 22px;
border: 1px solid $lightest-blue;
border-radius: 50%;
background-color: #fafafa;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-transition: all 0.25s ease;
-moz-transition: all 0.25s ease;
transition: all 0.25s ease;
}
.react-toggle--checked .react-toggle-thumb {
left: 27px;
border-color: #19ab27;
}
.react-toggle--focus .react-toggle-thumb {
-webkit-box-shadow: 0px 0px 3px 2px $blue;
-moz-box-shadow: 0px 0px 3px 2px $blue;
box-shadow: 0px 0px 2px 3px $blue;
}
.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {
-webkit-box-shadow: 0px 0px 5px 5px $blue;
-moz-box-shadow: 0px 0px 5px 5px $blue;
box-shadow: 0px 0px 5px 5px $blue;
}

View File

@@ -1,5 +1,6 @@
@import 'keyframes.scss'; @import 'keyframes.scss';
@import 'colors.scss'; @import 'colors.scss';
@import 'checkbox.scss';
*:not(ul) { *:not(ul) {
box-sizing: border-box; box-sizing: border-box;
@@ -84,6 +85,8 @@ h6 {
button:not(.reset) { button:not(.reset) {
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
text-transform: uppercase;
color: $white; color: $white;
background: $blue; background: $blue;
padding: 10px; padding: 10px;
@@ -92,8 +95,8 @@ button:not(.reset) {
transition: 0.15s; transition: 0.15s;
&:disabled { &:disabled {
cursor: default; cursor: not-allowed;
opacity: 0.5; opacity: 0.75;
} }
&:not(:disabled):hover { &:not(:disabled):hover {
@@ -131,11 +134,12 @@ input:not(.reset) {
background: $white; background: $white;
padding: 10px; padding: 10px;
border: 1px solid $lightest-grey; border: 1px solid $lightest-grey;
border-bottom: 3px solid $lightest-grey; border-bottom: 2px solid $lightest-grey;
border-radius: 5px;
transition: 0.15s; transition: 0.15s;
&:focus { &:focus {
border-bottom: 3px solid $blue; border-bottom: 2px solid $blue;
} }
} }
@@ -187,9 +191,7 @@ kbd {
padding: 0.25em 0.5em; padding: 0.25em 0.5em;
border-radius: 3px; border-radius: 3px;
border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(204, 204, 204);
box-shadow: box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;
0 1px 0 rgba(0, 0, 0, 0.2),
0 0 0 2px #ffffff inset;
display: inline-block; display: inline-block;
} }