revite/src/components/ui/ColourSwatches.tsx

163 lines
3.6 KiB
TypeScript
Raw Normal View History

import { Check } from "@styled-icons/boxicons-regular";
import { Palette } from "@styled-icons/boxicons-solid";
2021-06-18 10:57:08 -04:00
import styled, { css } from "styled-components";
2021-06-18 09:20:57 -04:00
import { RefObject } from "preact";
2021-07-06 14:29:27 -04:00
import { useRef } from "preact/hooks";
2021-07-05 06:23:23 -04:00
2021-12-15 13:23:05 -05:00
import { useDebounceCallback } from "../../lib/debounce";
2021-06-18 09:20:57 -04:00
interface Props {
2021-07-05 06:25:20 -04:00
value: string;
onChange: (value: string) => void;
2021-06-18 09:20:57 -04:00
}
const presets = [
2021-07-05 06:25:20 -04:00
[
"#7B68EE",
"#3498DB",
"#1ABC9C",
"#F1C40F",
"#FF7F50",
"#FD6671",
"#E91E63",
"#D468EE",
],
[
"#594CAD",
"#206694",
"#11806A",
"#C27C0E",
"#CD5B45",
"#FF424F",
"#AD1457",
"#954AA8",
],
2021-06-18 09:20:57 -04:00
];
const SwatchesBase = styled.div`
/*gap: 8px;*/
2021-07-05 06:25:20 -04:00
display: flex;
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
input {
width: 0;
height: 0;
top: 72px;
2021-07-05 06:25:20 -04:00
opacity: 0;
2021-07-08 09:03:41 -04:00
padding: 0;
border: 0;
position: relative;
2021-07-05 06:25:20 -04:00
pointer-events: none;
}
.overlay {
position: relative;
width: 0;
div {
width: 8px;
height: 68px;
background: linear-gradient(
to right,
var(--primary-background),
transparent
);
}
}
2021-06-18 09:20:57 -04:00
`;
2021-06-18 10:57:08 -04:00
const Swatch = styled.div<{ type: "small" | "large"; colour: string }>`
2021-07-05 06:25:20 -04:00
flex-shrink: 0;
cursor: pointer;
2021-07-10 10:42:13 -04:00
border-radius: var(--border-radius);
2021-07-05 06:25:20 -04:00
background-color: ${(props) => props.colour};
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
display: grid;
place-items: center;
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
&:hover {
border: 3px solid var(--foreground);
transition: border ease-in-out 0.07s;
}
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
svg {
color: white;
}
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
${(props) =>
props.type === "small"
? css`
width: 30px;
height: 30px;
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
svg {
/*stroke-width: 2;*/
}
`
: css`
width: 68px;
height: 68px;
`}
2021-06-18 09:20:57 -04:00
`;
const Rows = styled.div`
2021-07-05 06:25:20 -04:00
gap: 8px;
display: flex;
flex-direction: column;
overflow: auto;
2021-07-08 09:03:41 -04:00
padding-bottom: 4px;
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
> div {
gap: 8px;
display: flex;
flex-direction: row;
padding-inline-start: 8px;
}
2021-06-18 09:20:57 -04:00
`;
2021-06-18 10:18:10 -04:00
export default function ColourSwatches({ value, onChange }: Props) {
const ref = useRef<HTMLInputElement>() as RefObject<HTMLInputElement>;
2021-12-15 13:23:05 -05:00
const setValue = useDebounceCallback(
(value) => onChange(value as string),
[onChange],
100,
);
2021-06-18 09:20:57 -04:00
2021-07-05 06:25:20 -04:00
return (
<SwatchesBase>
<input
type="color"
value={value}
ref={ref}
2021-12-15 13:23:05 -05:00
onChange={(ev) => setValue(ev.currentTarget.value)}
2021-07-05 06:25:20 -04:00
/>
<Swatch
colour={value}
type="large"
onClick={() => ref.current?.click()}>
<Palette size={32} />
</Swatch>
<div class="overlay">
<div />
</div>
2021-07-05 06:25:20 -04:00
<Rows>
{presets.map((row, i) => (
<div key={i}>
{row.map((swatch, i) => (
<Swatch
colour={swatch}
type="small"
key={i}
onClick={() => onChange(swatch)}>
2021-07-06 11:42:32 -04:00
{swatch === value && <Check size={22} />}
2021-07-05 06:25:20 -04:00
</Swatch>
))}
</div>
))}
</Rows>
</SwatchesBase>
);
2021-06-18 09:20:57 -04:00
}