Search code examples
cssreactjsstyled-components

How to use Styled Components to "Fan out" a list of elements?


I'm trying to create a circular menu button where an invisible checkbox toggles the button to spin, and some buttons to appear in a fanning out motion to navigate to different pages at 9 o'clock and 11 o'clock.

This issue I have is that I can only control one or both as I can't differentiate and I don't want to create a new styled component for each one.

so everything in the code below works up until the:

&:checked ~ ${Button}:first-child {
            transform: translate(-50px, -50px);
    }
    &:checked ~ ${Button}:last-child {
            transform: translate(50px, -50px);
    }
`;

both of these use the "last-child" pseudo element.

Any help would be really appreciated. I'm sure it's just a simple fix but I can't figure it out.

TIA!

`

const Label = styled.label`
    position: fixed;
    bottom: 50px;
    right: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    cursor: pointer;
`;

const Vertical = styled.rect`
    transform-origin: center;
    transition: rotate 1s, opacity 1.5s;
`;

const Horizontal = styled.rect``;

const SVG = styled.svg`
    transform-origin: center;
    transition: all 2s;
`;

export const Button = styled.button`
    position: absolute;
    transition: all 1s;
    z-index: -1;
`;

export const CircleButton = styled.div`
    position: absolute;
    background: ${props => props.theme.accent};
    color: ${props => props.theme.text};
    height: ${props => props.size || "4rem"};
    width: ${props => props.size || "4rem"};
    margin: 1rem;
    font-size: 3rem;
    border: none;
    border-radius: 100px;
    box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
    display: flex;
    justify-content: center;
    align-items: center;
    transition: transform 2s;
    cursor: pointer;
    &:active {
        outline: none;
        box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.75);
    }
    z-index: 2;
`;

const Input = styled.input`
    position: absolute;
    z-index: 2;
    display: none;
    transition: all 2s;
    &:checked + ${CircleButton} {
        transform: rotate(720deg);
        ${SVG} {
            ${Vertical} {
                rotate: 90deg;
            }
        }
    }
    &:checked ~ ${Button}:first-child {
            transform: translate(-50px, -50px);
    }
    &:checked ~ ${Button}:last-child {
            transform: translate(50px, -50px);
    }
`;

export const Menu = () => {
    const list = [
        { title: "Water", link: "/Water" },
        { title: "Progress", link: "/Progess" }
    ];

    return (
        <div>
            <Label>
                <Input type="checkbox" onChange={() => console.log("check")} />
                <CircleButton>
                    <SVG viewBox="0 0 100 100" width="50px">
                        <Horizontal width="50" height="4" x="25" y="49" />
                        <Vertical width="4" height="50" x="49" y="25" />
                    </SVG>
                </CircleButton>
                {list.map((item, index) =>
                    <Button>
                        {item.title}
                    </Button>
                )}
            </Label>
        </div>
    );
};

`


Solution

  • I don't know, if i get your question correctly, but you could use nth-child like this:

    div:nth-child(even) button {
        background-color: red;
      }
      div:nth-child(odd) button {
        background-color: black;
      }
    

    For example the first one apply to every even element, the second one for every odd. The div, which i selected the nth-child from, is just the parent of the label element in your code. You could place several formula in this nth-child to select elements like an algorithm. Click here for more.

    Another option would be, to check in the css for specific values like the following:

        button[value="your button title"] {
                background-color: red;
              }
        
    but that is a bit hardcoded.
    

    In the list in your Menu function you could also pass a style. And then directly add it to your button that should be displayed.

    I hope i could help you, and not missunderstood your question.