Animated widget css integration

Hi,

I’m trying my first widget right now, now I want to include an animated arrow…how can I put this css code in the widget config?

body{
  margin: 0;
  padding: 0;
  #background-color: #fff;
}
.arrow{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
}
.arrow span{
    display: block;
    width: 20px;
    height: 20px;
    border-bottom: 5px solid #000;
    border-right: 5px solid #000;
    transform: rotate(135deg);
    margin: -25px;
    animation: animate 2s infinite;
}
.arrow span:nth-child(2){
    animation-delay: -0.2s;
}
.arrow span:nth-child(3){
    animation-delay: -0.4s;
}
@keyframes animate {
    0%{
        opacity: 0;
        transform: rotate(135deg) translate(-20px,-20px);
    }
    50%{
        opacity: 1;
    }
    100%{
        opacity: 0;
        transform: rotate(135deg) translate(20px,20px);
    }
}

Regards
Jörg

Search the forum for the ‘stylesheet’ property. There should be many good examples of how to use that to incorporate css directly into the widgets.

1 Like
 - component: f7-row
                              config:
                                stylesheet: >
                                 .arrow{
                                      position: absolute;
                                      top: 50%;
                                      left: 50%;
                                      transform: translate(-50%,-50%);
                                  }
                                  .arrow span{
                                      display: block;
                                      width: 20px;
                                      height: 20px;
                                      border-bottom: 5px solid #000;
                                      border-right: 5px solid #000;
                                      transform: rotate(135deg);
                                      margin: -25px;
                                      animation: animate 2s infinite;
                                  }
                                  .arrow span:nth-child(2){
                                      animation-delay: -0.2s;
                                  }
                                  .arrow span:nth-child(3){
                                      animation-delay: -0.4s;
                                  }
                                  @keyframes animate {
                                      0%{
                                          opacity: 0;
                                          transform: rotate(135deg) translate(-20px,-20px);
                                      }
                                      50%{
                                          opacity: 1;
                                      }
                                      100%{
                                          opacity: 0;
                                          transform: rotate(135deg) translate(20px,20px);
                                      }
                                  }

@JustinG Thanks for your reply…

Now I have integrated the code in the stylesheet, but I think my problem ist the .arrow how do I “connect” it, because nothing is visible…

By the css you’ve posted, arrow is a class. Many of the components that you add to a widget can have a class added to them via the config options. For example if you just want the arrow element to be a picture of an arrow (oh-icon doesn’t appear to be one of the ones you can add a class to directly so it needs to be wrapped in something else, like an f7-row):

- component: f7-row
  config:
    class:
      - arrow
  slots:
    default:
      - component: oh-icon
        config:
          icon: f7:arrow_right
1 Like

Can´t get this to work…

Nothing is diplayed:

uid: widget_pulse
tags: []
props:
  parameterGroups: []
timestamp: Mar 2, 2022, 3:31:04 PM
component: f7-card
config:
stylesheet: >
   .arrow{
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
    }
    .arrow span{
        display: block;
        width: 20px;
        height: 20px;
        border-bottom: 5px solid #000;
        border-right: 5px solid #000;
        transform: rotate(135deg);
        margin: -25px;
        animation: animate 2s infinite;
    }
    .arrow span:nth-child(2){
        animation-delay: -0.2s;
    }
    .arrow span:nth-child(3){
        animation-delay: -0.4s;
    }
    @keyframes animate {
        0%{
            opacity: 0;
            transform: rotate(135deg) translate(-20px,-20px);
        }
        50%{
            opacity: 1;
        }
        100%{
            opacity: 0;
            transform: rotate(135deg) translate(20px,20px);
        }
    }
slots:
  default:
    - component: oh-label-card
      style:
        class: arrow

There are a couple of issues here:

stylesheet has to be a child of the config settings so your indentation is off here.

class is a child of config also not style

I’m not sure why you’ve chosen an oh-label-card as your target, but whatever component you choose, you’ll need to remember that most of the components (and all of the oh specific ones, I believe) are compound elements. This means that you need to understand their construction in order to set a selector properly. Typically the easiest way to do this is to look at the vue files directly. For oh-label-card we see this:

The class configuration parameter is applied to a div parent of the span that holds the label. So if it’s the label you want to transform into your arrow animation your selector needs to be:

.arrow > span{

Fix those three issues and you get:
css_demo

1 Like

@JustinG Thanks again :+1:t3:

This works now:

component: f7-card
config:
  stylesheet: >
          .arrowleft {
               position: absolute;
               top: 100%;
               left: 50%;
               transform: translate(-50%,-50%);
           }
           .arrowleft span{
               display: block;
               width: 0.5em;
               height: 0.5em;
               border-bottom: 0.2em solid #000;
               border-right: 0.2em solid #000;
               transform: rotate(135deg);
               margin: -25px;
               animation: animate 2s infinite;
           }
           .arrowleft span:nth-child(2){
               animation-delay: -0.2s;
           }
           .arrowleft span:nth-child(3){
               animation-delay: -0.4s;
           }
           @keyframes animate {
               0%{
                   opacity: 0;
                   transform: rotate(135deg) translate(-1em,-1em);
               }
               50%{
                   opacity: 1;
               }
               100%{
                   opacity: 0;
                   transform: rotate(135deg) translate(1em,1em);
               }
           }
slots:
  default:
    - component: oh-label-card
      config:
        class: arrowleft

I am also not sure why :laughing:
It was a testing an try and error purpose…

I think only a

component: Label

would be better, because I don´t want the card…
But for component: Label I can´t find anything about…do you know how I can get it to work
with the component: Label ?

Label is, probably, one of the best options here for sheer simplicity. The class is applied directly to the div containing the label text:

This means that with no label text you get a nice empty div element to work with and it’s got the arrowleft class. So all you should need would be:

- component: Label
  config:
    class: arrowleft

and to change all of your selectors simply to .arrowleft.

1 Like

@JustinG Thank you for your patience :+1:t3:

Here ist my Code as you wrote, but nothing is shown:

uid: testwidget
tags: []
props: {}
timestamp: Mar 3, 2022, 5:27:14 PM
component: f7-card
config:
  stylesheet: >
    .arrowleft {
         position: absolute;
         top: 100%;
         left: 50%;
         transform: translate(-50%,-50%);
     }
    .arrowleft span{
         display: block;
         width: 0.5em;
         height: 0.5em;
         border-bottom: 0.2em solid #000;
         border-right: 0.2em solid #000;
         transform: rotate(135deg);
         margin: -25px;
         animation: animate 2s infinite;
     }
     .arrowleft span:nth-child(2){
         animation-delay: -0.2s;
     }
     .arrowleft span:nth-child(3){
         animation-delay: -0.4s;
     }
     @keyframes animate {
         0%{
             opacity: 0;
             transform: rotate(135deg) translate(-1em,-1em);
         }
         50%{
             opacity: 1;
         }
         100%{
             opacity: 0;
             transform: rotate(135deg) translate(1em,1em);
         }
     }
default:
- component: Label
  config:
    class: arrowleft

3 things:

First, somewhere along the way your slots dissappeared. So right now instead of

slots:
  default:

you just have

default:

which doesn’t mean anything.

Second, the f7-card will not render if there’s nothing for it to render and if the only thing on there is the empty label then there’s nothing to render (it doesn’t matter that you’re applying some fancy css to the label div, it’s still just an empty element as far as the card is concerned). So while you’re testing this out you’ll have to put something else there. Add some title text to the card add another component with some text or an icon, literally anything will do as long as there’s some content to be rendered.

Lastly, you didn’t change the css selectors when you shifted to the Label. The Label with the class produces

<div class="arrowleft"><div>

there are no span descendants so .arrowleft span as a selector doesn’t find anything. Your selector just needs to be only .arrowleft if you’re going to use the Label component.

1 Like
uid: Test_widget_css
tags: []
props: {}
timestamp: Mar 4, 2022, 9:12:10 AM
component: f7-card
config:
  stylesheet: >
    .arrowleft {
         position: absolute;
         top: 10em;
         left: 50%;
         transform: translate(-50%,-50%);
     }
    .arrowleft {
         display: block;
         width: 0.5em;
         height: 0.5em;
         border-bottom: 0.2em solid #000;
         border-right: 0.2em solid #000;
         transform: rotate(135deg);
         margin: -25px;
         animation: animate 2s infinite;
     }
     .arrowleft nth-child(2){
         animation-delay: -0.2s;
     }
     .arrowleft nth-child(3){
         animation-delay: -0.4s;
     }
     @keyframes animate {
         0%{
             opacity: 0;
             transform: rotate(135deg) translate(-1em,-1em);
         }
         50%{
             opacity: 1;
         }
         100%{
             opacity: 0;
             transform: rotate(135deg) translate(1em,1em);
         }
     }
slots:
  default:
    - component: Label
      config:
        style:
          font-size: 0.3em
          font-weight: bold
          text-align: center
        text: Hello World
    - component: Label
      config:
        class: arrowleft

This works ! Thank you very much @JustinG

1 Like

@JustinG Do you have an idea, how i can use it with the span selector ?
Or is there another way do make arrows like this ?

https://codepen.io/raf187/pen/BvgGRQ

Bacause without the span selectors it only shows one arrow

e3dc

The f7-row and f7-col components have a special property tag which lets you specify what element tag you want those components to be rendered with. If you want the animation to work with spans then you just need to have one f7-row (or anything else that makes an easy to use container) with the arrowleft class and then in that container you put three f7-row components that are each set to span:

- component: f7-row
  config:
    class: arrowleft
  slots:
    default:
      - component: f7-row
        config:
          tag: span
      - component: f7-row
        config:
          tag: span
      - component: f7-row
        config:
          tag: span

The beauty behind the css is that it doesn’t really matter exactly what the elements are as long as you understand the structure of your page and know how to get the selector that you want. Instead of using spans, you could stick with the Label components that you got working before (div elements), you just have to have a container that has the class and contains three labels, and then change your selectors accordingly:

- component: f7-row
  config:
    class: arrowleft
  slots:
    default:
      - component: Label
      - component: Label
      - component: Label

and

.arrowleft div {
  ...
1 Like

@JustinG Thanks agaín for your answer!

I tried your first Version but the animation with the other arrows is not shown…

uid: Test_widget_css
tags: []
timestamp: Mar 8, 2022, 9:22:37 AM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
slots:
  content:
    - component: f7-block
      config:
        style:
          --f7-theme-color: var(--f7-text-color)
          display: flex
        stylesheet: >
          .arrowright {
              display: block;
              width: 0.5em;
              height: 0.5em;
              border-bottom: 0.2em solid var(--f7-text-color);
              border-right: 0.2em solid var(--f7-text-color);
              transform: rotate(-45deg);
              #margin: -25px;
              animation: animate2 2s infinite;
          } .arrowright span nth-child(2){
              animation-delay: -0.2s;
          } .arrowright span nth-child(2){
              animation-delay: -0.4s;
          } @keyframes animate2 {
              0%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(-1em,-1em);
              }
              50%{
                  opacity: 1;
              }
              100%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(1em,1em);
              }
          }           
      slots:
        default:
          - component: f7-col
            config:
              desciption: Arrows second Column
              style:
                align-items: center
                display: flex
                flex-direction: column
                flex-grow: 1
          - component: f7-row
            config:
              class: arrowright
            slots:
              default:
                - component: f7-row
                  config:
                    tag: span
                - component: f7-row
                  config:
                    tag: span
                - component: f7-row
                  config:
                    tag: span

animine


With your second idea i get this

uid: Test_widget_css
tags: []
timestamp: Mar 8, 2022, 9:43:38 AM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
slots:
  content:
    - component: f7-block
      config:
        style:
          --f7-theme-color: var(--f7-text-color)
          display: flex
        stylesheet: >
          .arrowright {
              display: block;
              width: 0.5em;
              height: 0.5em;
              border-bottom: 0.2em solid var(--f7-text-color);
              border-right: 0.2em solid var(--f7-text-color);
              transform: rotate(-45deg);
              #margin: -25px;
              animation: animate2 2s infinite;
          } .arrowright div nth-child(2){
              animation-delay: -0.2s;
          } .arrowright div nth-child(3){
              animation-delay: -0.4s;
          } @keyframes animate2 {
              0%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(-1em,-1em);
              }
              50%{
                  opacity: 1;
              }
              100%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(1em,1em);
              }
          }           
      slots:
        default:
          - component: f7-col
            config:
              desciption: Arrows second Column
              style:
                align-items: center
                display: flex
                flex-direction: column
                flex-grow: 1
          - component: f7-row
            config:
              class: arrowright
            slots:
              default:
                - component: Label
                  config:
                    class: arrowright div                
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div                   

animine2

In both cases, you’ve lost part of the original structure of the css code. Look back at what you first posted, the only styling that was applied to the container was the positional information (.arrow), all the rest was applied to the child spans (.arrow span) and then the delays were applied to specific children via the nth-child pseudoclass (.arrow span:nth-child ← note must use the colon which has also gone missing from your code at this point).

What you’ve posted here has most of the styling applied to the container, which was one of our first working models when we were only using one arrow, but now that you want to have multiple arrows, you have to make sure that you are applying the stylings at the correct level.

.arrowright {
  ... positional styles for the entire block of arrows, if you care
}

.arrowright span {
  ...how to turn every child span of arrowright into an arrow by turning it and drawing some of the box borders and then animate each arrow exactly the same way
}

.arrowright span:n-th(2) {
  ...but we want the second child arrow to have  a slightly different animation timing
}

.arrowright span:n-th(3) {
  ...and we want the third child arrow to have  another slightly different animation timing
}
1 Like

I tried again with this:

uid: Test_widget_css
tags: []
timestamp: Mar 8, 2022, 10:33:31 AM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
slots:
  content:
    - component: f7-block
      config:
        style:
          --f7-theme-color: var(--f7-text-color)
          display: flex
        stylesheet: >
          .arrowright {
             position: absolute;
             top: 10em;
             left: 50%;
             transform: translate(-50%,-50%);
           }
          .arrowright div {
             display: block;
             width: 0.5em;
             height: 0.5em;
             border-bottom: 0.2em solid #000;
             border-right: 0.2em solid #000;
             transform: rotate(135deg);
             margin: -25px;
             animation: animate2 2s infinite;
          }
          .arrowright div:nth-child(2) {
              animation-delay: -0.2s;
          }  
          .arrowright div:nth-child(3) {
              animation-delay: -0.4s;
          }  
          @keyframes animate2 {
              0%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(-1em,-1em);
              }
              50%{
                  opacity: 1;
              }
              100%{
                  opacity: 0;
                  transform: rotate(-45deg) translate(1em,1em);
              }
          }           
      slots:
        default:
          - component: f7-col
            config:
              desciption: Arrows second Column
              style:
                align-items: center
                display: flex
                flex-direction: column
                flex-grow: 1
          - component: f7-row
            config:
              class: arrowright
            slots:
              default:
                - component: Label
                  config:
                    class: arrowright div                
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div  

And nothin is shown :frowning:

This is, in fact, mostly correct! And when I paste this exact code into my widget editor, I see the three moving arrows…it’s just that they’re waaaay down the screen:
image
Do note, that sometimes with complex stylesheet properties like this, the widget editor’s autorefresh isn’t always reliable; if you’ve changed something and don’t see the expected result, hit the Redraw link at the bottom or press ctrl + r.

So now that it works, let’s clean it up a bit:

First, it’s moved so far down the page because of the positioning in the .arrowright block. Specifically: setting the position of the block to absolute means that instead of following the position set by it’s parent element, it is just placed in the upper-left corner of the view. Then the top: 10em moves the top of the element down from that starting point 10 * the text size (i.e., way down the page). For these testing purposes, you probably don’t need any of that positioning, although you may later when you want to put this on other widgets.

Second, this will all make a little more sense to you, I suspect, if you read up on css selectors (my first choice of css references is usually the w3schools.com site, but there are hundreds of good options). You’ll see that your

class: arrowright div

on the Label components isn’t very meaningful and isn’t contributing anything in this case (see my post a couple up with the completely blank Label components). If you’re using the Label components, then they ARE a div element already; that’s how they’re built. So, in your css the .arrowright div block first looks for every element that has the arrowright class (the . in front means this is a class name). If it finds something with that class (in this case the f7-row component) then it looks at the next part, div, and it knows to look for each div element that is inside (a child of) the element it just found with the arrowright class. If it finds any element matching that description (and it will if there are Label components in there) then it applies the styles in that block to that element. It never even has to look at the class of the Labels because it has already found its match.

In the two following blocks, the same process is used except instead of matching ALL the div elements inside the arrowright class element, it ONLY matches a div if it is the 2nd or the 3rd div in sequence.

1 Like

@JustinG Thank´s again, I learned a lot :+1:

I know also cleaned my code…

uid: Test_widget_css
tags: []
props:
  parameters:
  parameterGroups: []
timestamp: Mar 9, 2022, 4:44:18 PM
component: f7-card
config:
  style:
    padding: 1%
    justify-content: center
  class:
    - display-flex
    - align-items-center
  stylesheet: >
    .arrowleft {
       #position: absolute;
       #top: 50%;
       #left: 50%;
       #transform: translate(50%,50%);
     }
    .arrowleft div {
       display: block;
       width: 0.5em;
       height: 0.5em;
       border-bottom: 0.2em solid var(--f7-text-color);
       border-right: 0.2em solid var(--f7-text-color);
       transform: rotate(135deg);
       #margin: -25px;
       animation: animate 2s infinite;
    }  .arrowleft div:nth-child(2){
        animation-delay: -0.2s;
    }  .arrowleft div:nth-child(3){
        animation-delay: -0.4s;
    }  @keyframes animate {
        0%{
            opacity: 0;
            transform: rotate(135deg) translate(-1em,-1em);
        }
        50%{
            opacity: 1;
        }
        100%{
            opacity: 0;
            transform: rotate(135deg) translate(1em,1em);
        }
    }                 
    .arrowright {
       #position: absolute;
       #top: 50%;
       #left: 50%;
       #transform: translate(-50%,-50%);
     }
    .arrowright div {
       display: block;
       width: 0.5em;
       height: 0.5em;
       border-bottom: 0.2em solid var(--f7-text-color);
       border-right: 0.2em solid var(--f7-text-color);
       transform: rotate(135deg);
       #margin: -25px;
       animation: animate2 2s infinite;
    }    .arrowright div:nth-child(2) {
        animation-delay: -0.2s;
    }      .arrowright div:nth-child(3) {
        animation-delay: -0.4s;
    }     
    @keyframes animate2 {
        0%{
            opacity: 0;
            transform: rotate(-45deg) translate(-1em,-1em);
        }
        50%{
            opacity: 1;
        }
        100%{
            opacity: 0;
            transform: rotate(-45deg) translate(1em,1em);
        }
    }                   
slots:
  default:
    - component: f7-col
      config:
        style:
          align-items: center
          display: flex
          flex-direction: column
          justify-content: center
          width: 20%
      slots:
        default:
          - component: f7-row
            config:
              class: arrowright
            slots:
              default:
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div
          - component: f7-row
            config:
              class: arrowleft
            slots:
              default:
                - component: Label
                  config:
                    class: arrowleft div
                - component: Label
                  config:
                    class: arrowleft div
                - component: Label
                  config:
                    class: arrowleft div

But now I have two different styles, when I make an arrowleft and a arrowright:

animine3

I find the arrowleft nicer, but I can´t find out why the animation does not look the same :neutral_face:

The issue is with your animation-delay settings. When the three arrow elements are drawn they are placed first, second, third from left to right for both the arrowright and arrowleft styles. Then you apply the animation which causes each element to move either to the right or the left. BUT, in both cases you have the animation-delay set so that each element will move in the same order:

  • Element one (left) has delay 0: it will move last
  • Element two (middle) has delay -0.2: it will move second
  • Element three (right) has delay -0.4: it will move first
    So, if the arrows are moving right, the one on the right will move first pulling away from the others, followed by the one in the middle which will then pull away from the one on the left: It looks like the arrows are spreading apart. However, if the arrows are moving left, the one on the right will move first, moving trowards the middle one which will then start moving towards the left one: it looks like the arrows are bunching together.

Solution: change the signs on the animation-delay for the arrowright and then it will look like the arrowleft.

1 Like

@JustinG I can’t thank you enough :+1:t3:

I changed that and in principle it works too, but with the arrowright there are always two arrows in the wrong position on the first run. From the second round everything works fine…

uid: Test_widget_css
tags: []
props:
  parameterGroups: []
timestamp: Mar 10, 2022, 9:39:22 AM
component: f7-card
config:
  style:
    padding: 1%
    justify-content: center
  class:
    - display-flex
    - align-items-center
  stylesheet: >
    .arrowleft {
       #position: absolute;
       #top: 50%;
       #left: 50%;
       #transform: translate(50%,50%);
     }
    .arrowleft div {
       display: block;
       width: 0.4em;
       height: 0.4em;
       border-bottom: 0.15em solid var(--f7-text-color);
       border-right: 0.15em solid var(--f7-text-color);
       transform: rotate(135deg);
       #margin: -25px;
       animation: animate 2s infinite;
    }  .arrowleft div:nth-child(2){
        animation-delay: -0.2s;
    }  .arrowleft div:nth-child(3){
        animation-delay: -0.4s;
    } @keyframes animate {
        0%{
            opacity: 0;
            transform: rotate(135deg) translate(-1em,-1em);
        }
        50%{
            opacity: 1;
        }
        100%{
            opacity: 0;
            transform: rotate(135deg) translate(1em,1em);
        }
    } .arrowright {
       #position: absolute;
       #top: 50%;
       #left: 50%;
       #transform: translate(-50%,-50%);
     }
    .arrowright div {
       display: block;
       width: 0.4em;
       height: 0.4em;
       border-bottom: 0.15em solid var(--f7-text-color);
       border-right: 0.15em solid var(--f7-text-color);
       transform: rotate(-45deg);
       #margin: -25px;
       animation: animate2 2s infinite;
    }
    .arrowright div:nth-child(2) {
        animation-delay: 0.2s;
    }
    .arrowright div:nth-child(3) {
        animation-delay: 0.4s;
    }
    @keyframes animate2 {
        0%{
            opacity: 0;
            transform: rotate(-45deg) translate(-1em,-1em);
        }
        50%{
            opacity: 1;
        }
        100%{
            opacity: 0;
            transform: rotate(-45deg) translate(1em,1em);
        }
    }                   
slots:
  default:
    - component: f7-col
      config:
        style:
          align-items: center
          display: flex
          flex-direction: column
          justify-content: center
          width: 20%
      slots:
        default:
          - component: f7-row
            config:
              class: arrowright
            slots:
              default:
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div
                - component: Label
                  config:
                    class: arrowright div
          - component: f7-row
            config:
              class: arrowleft
            slots:
              default:
                - component: Label
                  config:
                    class: arrowleft div
                - component: Label
                  config:
                    class: arrowleft div
                - component: Label
                  config:
                    class: arrowleft div

animine4