Skip to content
Snippets Groups Projects
ColourSwatches.tsx 3.41 KiB
Newer Older
import { Check } from "@styled-icons/boxicons-regular";
import { Palette } from "@styled-icons/boxicons-solid";
insert's avatar
insert committed
import styled, { css } from "styled-components";
insert's avatar
insert committed

insert's avatar
insert committed
import { RefObject } from "preact";
insert's avatar
insert committed
import { useRef } from "preact/hooks";
insert's avatar
insert committed

insert's avatar
insert committed
interface Props {
    value: string;
    onChange: (value: string) => void;
insert's avatar
insert committed
}

const presets = [
    [
        "#7B68EE",
        "#3498DB",
        "#1ABC9C",
        "#F1C40F",
        "#FF7F50",
        "#FD6671",
        "#E91E63",
        "#D468EE",
    ],
    [
        "#594CAD",
        "#206694",
        "#11806A",
        "#C27C0E",
        "#CD5B45",
        "#FF424F",
        "#AD1457",
        "#954AA8",
    ],
insert's avatar
insert committed
];

const SwatchesBase = styled.div`
    /*gap: 8px;*/
    display: flex;
    input {
insert's avatar
insert committed
        width: 0;
        height: 0;
        top: 72px;
        opacity: 0;
        padding: 0;
        border: 0;
insert's avatar
insert committed
        position: relative;
        pointer-events: none;
    }
insert's avatar
insert committed

    .overlay {
        position: relative;
        width: 0;

        div {
            width: 8px;
            height: 68px;
            background: linear-gradient(
                to right,
                var(--primary-background),
                transparent
            );
insert's avatar
insert committed
const Swatch = styled.div<{ type: "small" | "large"; colour: string }>`
    flex-shrink: 0;
    cursor: pointer;
    border-radius: var(--border-radius);
    background-color: ${(props) => props.colour};
    display: grid;
    place-items: center;
    &:hover {
        border: 3px solid var(--foreground);
        transition: border ease-in-out 0.07s;
    }
    svg {
        color: white;
    }
    ${(props) =>
        props.type === "small"
            ? css`
                  width: 30px;
                  height: 30px;
                  svg {
                      /*stroke-width: 2;*/
                  }
              `
            : css`
                  width: 68px;
                  height: 68px;
              `}
insert's avatar
insert committed
`;

const Rows = styled.div`
    gap: 8px;
    display: flex;
    flex-direction: column;
    overflow: auto;
    padding-bottom: 4px;
    > div {
        gap: 8px;
        display: flex;
        flex-direction: row;
        padding-inline-start: 8px;
    }
export default function ColourSwatches({ value, onChange }: Props) {
insert's avatar
insert committed
    const ref = useRef<HTMLInputElement>() as RefObject<HTMLInputElement>;
    return (
        <SwatchesBase>
            <input
                type="color"
                value={value}
                ref={ref}
                onChange={(ev) => onChange(ev.currentTarget.value)}
            />
insert's avatar
insert committed
            <Swatch
                colour={value}
                type="large"
                onClick={() => ref.current?.click()}>
                <Palette size={32} />
            </Swatch>

            <div class="overlay">
                <div />
            </div>

            <Rows>
                {presets.map((row, i) => (
                    <div key={i}>
                        {row.map((swatch, i) => (
                            <Swatch
                                colour={swatch}
                                type="small"
                                key={i}
                                onClick={() => onChange(swatch)}>
                                {swatch === value && <Check size={22} />}
                            </Swatch>
                        ))}
                    </div>
                ))}
            </Rows>
        </SwatchesBase>
    );
insert's avatar
insert committed
}