Merge pull request #80 from snowball-tools/ayungavis/T-4838-checkbox
[T-4838: feat] Checkbox component
This commit is contained in:
commit
76c59e2c58
@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/inter": "^5.0.16",
|
"@fontsource/inter": "^5.0.16",
|
||||||
"@material-tailwind/react": "^2.1.7",
|
"@material-tailwind/react": "^2.1.7",
|
||||||
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
import { tv, type VariantProps } from 'tailwind-variants';
|
||||||
|
|
||||||
|
export const getCheckboxVariant = tv({
|
||||||
|
slots: {
|
||||||
|
wrapper: ['group', 'flex', 'gap-3'],
|
||||||
|
indicator: [
|
||||||
|
'grid',
|
||||||
|
'place-content-center',
|
||||||
|
'text-transparent',
|
||||||
|
'group-hover:text-controls-disabled',
|
||||||
|
'focus-visible:text-controls-disabled',
|
||||||
|
'group-focus-visible:text-controls-disabled',
|
||||||
|
'data-[state=checked]:text-elements-on-primary',
|
||||||
|
'data-[state=checked]:group-focus-visible:text-elements-on-primary',
|
||||||
|
'data-[state=indeterminate]:text-elements-on-primary',
|
||||||
|
'data-[state=checked]:data-[disabled]:text-elements-on-disabled-active',
|
||||||
|
],
|
||||||
|
icon: ['w-3', 'h-3', 'stroke-current', 'text-current'],
|
||||||
|
input: [
|
||||||
|
'h-5',
|
||||||
|
'w-5',
|
||||||
|
'group',
|
||||||
|
'border',
|
||||||
|
'border-border-interactive/10',
|
||||||
|
'bg-controls-tertiary',
|
||||||
|
'rounded-md',
|
||||||
|
'transition-all',
|
||||||
|
'duration-150',
|
||||||
|
'focus-ring',
|
||||||
|
'shadow-button',
|
||||||
|
'group-hover:border-border-interactive/[0.14]',
|
||||||
|
'group-hover:bg-controls-tertiary',
|
||||||
|
'data-[state=checked]:bg-controls-primary',
|
||||||
|
'data-[state=checked]:hover:bg-controls-primary-hovered',
|
||||||
|
'data-[state=checked]:focus-visible:bg-controls-primary-hovered',
|
||||||
|
'data-[disabled]:bg-controls-disabled',
|
||||||
|
'data-[disabled]:shadow-none',
|
||||||
|
'data-[disabled]:hover:border-border-interactive/10',
|
||||||
|
'data-[disabled]:cursor-not-allowed',
|
||||||
|
'data-[state=checked]:data-[disabled]:bg-controls-disabled-active',
|
||||||
|
],
|
||||||
|
label: [
|
||||||
|
'text-sm',
|
||||||
|
'tracking-[-0.006em]',
|
||||||
|
'text-elements-high-em',
|
||||||
|
'flex',
|
||||||
|
'flex-col',
|
||||||
|
'gap-1',
|
||||||
|
'px-1',
|
||||||
|
],
|
||||||
|
description: ['text-xs', 'text-elements-low-em'],
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
disabled: {
|
||||||
|
true: {
|
||||||
|
wrapper: ['cursor-not-allowed'],
|
||||||
|
indicator: ['group-hover:text-transparent'],
|
||||||
|
input: [
|
||||||
|
'group-hover:border-border-interactive/[0.14]',
|
||||||
|
'group-hover:bg-controls-disabled',
|
||||||
|
],
|
||||||
|
label: ['cursor-not-allowed'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CheckboxVariants = VariantProps<typeof getCheckboxVariant>;
|
@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as CheckboxRadix from '@radix-ui/react-checkbox';
|
||||||
|
import { type CheckboxProps as CheckboxRadixProps } from '@radix-ui/react-checkbox';
|
||||||
|
|
||||||
|
import { getCheckboxVariant, type CheckboxVariants } from './Checkbox.theme';
|
||||||
|
import { CheckIcon } from 'components/shared/CustomIcon';
|
||||||
|
|
||||||
|
interface CheckBoxProps extends CheckboxRadixProps, CheckboxVariants {
|
||||||
|
/**
|
||||||
|
* The label of the checkbox.
|
||||||
|
*/
|
||||||
|
label?: string;
|
||||||
|
/**
|
||||||
|
* The description of the checkbox.
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checkbox component is used to allow users to select one or more items from a set.
|
||||||
|
* It is a wrapper around the `@radix-ui/react-checkbox` component.
|
||||||
|
*
|
||||||
|
* It accepts all the props from `@radix-ui/react-checkbox` component and the variants from the theme.
|
||||||
|
*
|
||||||
|
* It also accepts `label` and `description` props to display the label and description of the checkbox.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* <Checkbox
|
||||||
|
* id="checkbox"
|
||||||
|
* label="Checkbox"
|
||||||
|
* description="This is a checkbox"
|
||||||
|
* />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const Checkbox = ({
|
||||||
|
id,
|
||||||
|
className,
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
onCheckedChange,
|
||||||
|
...props
|
||||||
|
}: CheckBoxProps) => {
|
||||||
|
const {
|
||||||
|
wrapper: wrapperStyle,
|
||||||
|
indicator: indicatorStyle,
|
||||||
|
icon: iconStyle,
|
||||||
|
input: inputStyle,
|
||||||
|
label: labelStyle,
|
||||||
|
description: descriptionStyle,
|
||||||
|
} = getCheckboxVariant({
|
||||||
|
disabled: props?.disabled,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div className={wrapperStyle()}>
|
||||||
|
<CheckboxRadix.Root
|
||||||
|
{...props}
|
||||||
|
className={inputStyle({ className })}
|
||||||
|
id={id}
|
||||||
|
onCheckedChange={onCheckedChange}
|
||||||
|
>
|
||||||
|
<CheckboxRadix.Indicator forceMount className={indicatorStyle()}>
|
||||||
|
<CheckIcon className={iconStyle()} />
|
||||||
|
</CheckboxRadix.Indicator>
|
||||||
|
</CheckboxRadix.Root>
|
||||||
|
{label && (
|
||||||
|
<label className={labelStyle()} htmlFor={id}>
|
||||||
|
{label}
|
||||||
|
{description && (
|
||||||
|
<span className={descriptionStyle()}>{description}</span>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './Checkbox';
|
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { CustomIcon, CustomIconProps } from './CustomIcon';
|
||||||
|
|
||||||
|
export const CheckIcon = (props: CustomIconProps) => {
|
||||||
|
return (
|
||||||
|
<CustomIcon
|
||||||
|
width="12"
|
||||||
|
height="12"
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M1.5 7.5L4.64706 10L10.5 2"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</CustomIcon>
|
||||||
|
);
|
||||||
|
};
|
@ -1,5 +1,6 @@
|
|||||||
export * from './PlusIcon';
|
export * from './PlusIcon';
|
||||||
export * from './CustomIcon';
|
export * from './CustomIcon';
|
||||||
|
export * from './CheckIcon';
|
||||||
export * from './ChevronGrabberHorizontal';
|
export * from './ChevronGrabberHorizontal';
|
||||||
export * from './ChevronLeft';
|
export * from './ChevronLeft';
|
||||||
export * from './ChevronRight';
|
export * from './ChevronRight';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Button, ButtonOrLinkProps } from 'components/shared/Button';
|
import { Button, ButtonOrLinkProps } from 'components/shared/Button';
|
||||||
import { Calendar } from 'components/shared/Calendar';
|
import { Calendar } from 'components/shared/Calendar';
|
||||||
|
import { Checkbox } from 'components/shared/Checkbox';
|
||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Value } from 'react-calendar/dist/cjs/shared/types';
|
import { Value } from 'react-calendar/dist/cjs/shared/types';
|
||||||
@ -77,6 +78,36 @@ const Page = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full h border border-gray-200 px-20 my-10" />
|
<div className="w-full h border border-gray-200 px-20 my-10" />
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-10 items-center justify-between">
|
||||||
|
<h1 className="text-2xl font-bold">Checkbox</h1>
|
||||||
|
<div className="flex gap-10 flex-wrap">
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<Checkbox
|
||||||
|
id={`checkbox-${index + 1}`}
|
||||||
|
key={index}
|
||||||
|
label={`Label ${index + 1}`}
|
||||||
|
disabled={index === 2 || index === 4 ? true : false}
|
||||||
|
checked={index === 4 ? true : undefined}
|
||||||
|
value={`value-${index + 1}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-10 flex-wrap">
|
||||||
|
{Array.from({ length: 2 }).map((_, index) => (
|
||||||
|
<Checkbox
|
||||||
|
id={`checkbox-description-${index + 1}`}
|
||||||
|
key={index}
|
||||||
|
label={`Label ${index + 1}`}
|
||||||
|
description={`Description of the checkbox ${index + 1}`}
|
||||||
|
value={`value-with-description-${index + 1}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full h border border-gray-200 px-20 my-10" />
|
||||||
|
|
||||||
<div className="flex flex-col gap-10 items-center justify-between">
|
<div className="flex flex-col gap-10 items-center justify-between">
|
||||||
<h1 className="text-2xl font-bold">Calendar</h1>
|
<h1 className="text-2xl font-bold">Calendar</h1>
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
|
100
yarn.lock
100
yarn.lock
@ -1280,7 +1280,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
||||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||||
|
|
||||||
"@babel/runtime@^7.10.4", "@babel/runtime@^7.23.7", "@babel/runtime@^7.3.1":
|
"@babel/runtime@^7.10.4", "@babel/runtime@^7.13.10", "@babel/runtime@^7.23.7", "@babel/runtime@^7.3.1":
|
||||||
version "7.23.9"
|
version "7.23.9"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
|
||||||
integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
|
integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
|
||||||
@ -3277,6 +3277,104 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||||
|
|
||||||
|
"@radix-ui/primitive@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
|
||||||
|
integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-checkbox@^1.0.4":
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz#98f22c38d5010dd6df4c5744cac74087e3275f4b"
|
||||||
|
integrity sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/primitive" "1.0.1"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
"@radix-ui/react-context" "1.0.1"
|
||||||
|
"@radix-ui/react-presence" "1.0.1"
|
||||||
|
"@radix-ui/react-primitive" "1.0.3"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||||
|
"@radix-ui/react-use-previous" "1.0.1"
|
||||||
|
"@radix-ui/react-use-size" "1.0.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-compose-refs@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
|
||||||
|
integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-context@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
|
||||||
|
integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-presence@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
|
||||||
|
integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-primitive@1.0.3":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
||||||
|
integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-slot" "1.0.2"
|
||||||
|
|
||||||
|
"@radix-ui/react-slot@1.0.2":
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||||
|
integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-callback-ref@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
|
||||||
|
integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-controllable-state@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286"
|
||||||
|
integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-layout-effect@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399"
|
||||||
|
integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-previous@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66"
|
||||||
|
integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-size@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2"
|
||||||
|
integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||||
|
|
||||||
"@remix-run/router@1.13.1":
|
"@remix-run/router@1.13.1":
|
||||||
version "1.13.1"
|
version "1.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.13.1.tgz#07e2a8006f23a3bc898b3f317e0a58cc8076b86e"
|
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.13.1.tgz#07e2a8006f23a3bc898b3f317e0a58cc8076b86e"
|
||||||
|
Loading…
Reference in New Issue
Block a user