Compare commits
17 Commits
jitihouse/
...
shipit-rea
|
@ -0,0 +1,97 @@
|
|||
.animation-target {
|
||||
-webkit-animation: animation 5800ms linear both;
|
||||
animation: animation 5800ms linear both;
|
||||
}
|
||||
|
||||
/* Generated with Bounce.js. Edit at https://goo.gl/N4iuvQ */
|
||||
|
||||
@-webkit-keyframes animation {
|
||||
0% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); }
|
||||
0.55% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.621, 1, 0, 0, 0, 0, 1, 0, -872.394, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.621, 1, 0, 0, 0, 0, 1, 0, -872.394, 0, 0, 1); }
|
||||
1.1% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.829, 1, 0, 0, 0, 0, 1, 0, -758.053, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.829, 1, 0, 0, 0, 0, 1, 0, -758.053, 0, 0, 1); }
|
||||
2.19% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.477, 1, 0, 0, 0, 0, 1, 0, -568.124, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.477, 1, 0, 0, 0, 0, 1, 0, -568.124, 0, 0, 1); }
|
||||
2.21% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.47, 1, 0, 0, 0, 0, 1, 0, -565.455, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.47, 1, 0, 0, 0, 0, 1, 0, -565.455, 0, 0, 1); }
|
||||
3.26% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.146, 1, 0, 0, 0, 0, 1, 0, -420.951, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.146, 1, 0, 0, 0, 0, 1, 0, -420.951, 0, 0, 1); }
|
||||
4.35% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.003, 1, 0, 0, 0, 0, 1, 0, -304.986, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.003, 1, 0, 0, 0, 0, 1, 0, -304.986, 0, 0, 1); }
|
||||
4.42% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.007, 1, 0, 0, 0, 0, 1, 0, -298.617, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.007, 1, 0, 0, 0, 0, 1, 0, -298.617, 0, 0, 1); }
|
||||
5.42% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.033, 1, 0, 0, 0, 0, 1, 0, -217.83, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.033, 1, 0, 0, 0, 0, 1, 0, -217.83, 0, 0, 1); }
|
||||
6.63% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.019, 1, 0, 0, 0, 0, 1, 0, -144.967, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.019, 1, 0, 0, 0, 0, 1, 0, -144.967, 0, 0, 1); }
|
||||
8.84% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.001, 1, 0, 0, 0, 0, 1, 0, -62.157, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.001, 1, 0, 0, 0, 0, 1, 0, -62.157, 0, 0, 1); }
|
||||
9.73% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, -41.642, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, -41.642, 0, 0, 1); }
|
||||
13.25% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2.427, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2.427, 0, 0, 1); }
|
||||
13.69% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.405, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.405, 0, 0, 1); }
|
||||
13.79% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
|
||||
14.05% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.95, -7.992, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.95, -7.992, 0, 1); }
|
||||
14.41% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.112, -15.312, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.112, -15.312, 0, 1); }
|
||||
15.04% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.621, -19.275, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.621, -19.275, 0, 1); }
|
||||
15.81% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4.842, -15.606, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4.842, -15.606, 0, 1); }
|
||||
16.57% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.493, -9.111, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.493, -9.111, 0, 1); }
|
||||
17.24% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.739, -4.058, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.739, -4.058, 0, 1); }
|
||||
17.35% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.755, -3.395, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.755, -3.395, 0, 1); }
|
||||
17.67% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.772, -1.664, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.772, -1.664, 0, 1); }
|
||||
18.11% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.729, -0.013, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.729, -0.013, 0, 1); }
|
||||
19.35% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.306, -1.622, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.306, -1.622, 0, 1); }
|
||||
22.42% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.532, -0.002, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.532, -0.002, 0, 1); }
|
||||
23.67% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.828, -0.137, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.828, -0.137, 0, 1); }
|
||||
26.74% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.477, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.477, 0, 0, 1); }
|
||||
27.98% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.095, -0.011, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.095, -0.011, 0, 1); }
|
||||
30.93% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.495, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.495, 0, 0, 1); }
|
||||
31.03% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.481, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.481, 0, 0, 1); }
|
||||
34% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 514.458, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 514.458, 0, 0, 1); }
|
||||
36.97% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 878.645, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 878.645, 0, 0, 1); }
|
||||
39.94% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1052.286, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1052.286, 0, 0, 1); }
|
||||
42.91% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1093.33, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1093.33, 0, 0, 1); }
|
||||
45.29% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1078.742, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1078.742, 0, 0, 1); }
|
||||
50.57% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1020.622, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1020.622, 0, 0, 1); }
|
||||
58.23% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 993.768, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 993.768, 0, 0, 1); }
|
||||
68.97% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.903, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.903, 0, 0, 1); }
|
||||
73.56% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000.416, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000.416, 0, 0, 1); }
|
||||
88.95% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.972, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.972, 0, 0, 1); }
|
||||
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 1); }
|
||||
}
|
||||
|
||||
@keyframes animation {
|
||||
0% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); }
|
||||
0.55% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.621, 1, 0, 0, 0, 0, 1, 0, -872.394, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.621, 1, 0, 0, 0, 0, 1, 0, -872.394, 0, 0, 1); }
|
||||
1.1% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.829, 1, 0, 0, 0, 0, 1, 0, -758.053, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.829, 1, 0, 0, 0, 0, 1, 0, -758.053, 0, 0, 1); }
|
||||
2.19% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.477, 1, 0, 0, 0, 0, 1, 0, -568.124, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.477, 1, 0, 0, 0, 0, 1, 0, -568.124, 0, 0, 1); }
|
||||
2.21% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.47, 1, 0, 0, 0, 0, 1, 0, -565.455, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.47, 1, 0, 0, 0, 0, 1, 0, -565.455, 0, 0, 1); }
|
||||
3.26% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.146, 1, 0, 0, 0, 0, 1, 0, -420.951, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.146, 1, 0, 0, 0, 0, 1, 0, -420.951, 0, 0, 1); }
|
||||
4.35% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.003, 1, 0, 0, 0, 0, 1, 0, -304.986, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.003, 1, 0, 0, 0, 0, 1, 0, -304.986, 0, 0, 1); }
|
||||
4.42% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.007, 1, 0, 0, 0, 0, 1, 0, -298.617, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.007, 1, 0, 0, 0, 0, 1, 0, -298.617, 0, 0, 1); }
|
||||
5.42% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.033, 1, 0, 0, 0, 0, 1, 0, -217.83, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.033, 1, 0, 0, 0, 0, 1, 0, -217.83, 0, 0, 1); }
|
||||
6.63% { -webkit-transform: matrix3d(1, 0, 0, 0, -0.019, 1, 0, 0, 0, 0, 1, 0, -144.967, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, -0.019, 1, 0, 0, 0, 0, 1, 0, -144.967, 0, 0, 1); }
|
||||
8.84% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.001, 1, 0, 0, 0, 0, 1, 0, -62.157, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.001, 1, 0, 0, 0, 0, 1, 0, -62.157, 0, 0, 1); }
|
||||
9.73% { -webkit-transform: matrix3d(1, 0, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, -41.642, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, -41.642, 0, 0, 1); }
|
||||
13.25% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2.427, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2.427, 0, 0, 1); }
|
||||
13.69% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.405, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.405, 0, 0, 1); }
|
||||
13.79% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
|
||||
14.05% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.95, -7.992, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.95, -7.992, 0, 1); }
|
||||
14.41% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.112, -15.312, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.112, -15.312, 0, 1); }
|
||||
15.04% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.621, -19.275, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.621, -19.275, 0, 1); }
|
||||
15.81% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4.842, -15.606, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4.842, -15.606, 0, 1); }
|
||||
16.57% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.493, -9.111, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.493, -9.111, 0, 1); }
|
||||
17.24% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.739, -4.058, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.739, -4.058, 0, 1); }
|
||||
17.35% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.755, -3.395, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.755, -3.395, 0, 1); }
|
||||
17.67% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.772, -1.664, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.772, -1.664, 0, 1); }
|
||||
18.11% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.729, -0.013, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.729, -0.013, 0, 1); }
|
||||
19.35% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.306, -1.622, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.306, -1.622, 0, 1); }
|
||||
22.42% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.532, -0.002, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.532, -0.002, 0, 1); }
|
||||
23.67% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.828, -0.137, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.828, -0.137, 0, 1); }
|
||||
26.74% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.477, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.477, 0, 0, 1); }
|
||||
27.98% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.095, -0.011, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.095, -0.011, 0, 1); }
|
||||
30.93% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.495, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.495, 0, 0, 1); }
|
||||
31.03% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.481, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.481, 0, 0, 1); }
|
||||
34% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 514.458, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 514.458, 0, 0, 1); }
|
||||
36.97% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 878.645, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 878.645, 0, 0, 1); }
|
||||
39.94% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1052.286, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1052.286, 0, 0, 1); }
|
||||
42.91% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1093.33, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1093.33, 0, 0, 1); }
|
||||
45.29% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1078.742, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1078.742, 0, 0, 1); }
|
||||
50.57% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1020.622, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1020.622, 0, 0, 1); }
|
||||
58.23% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 993.768, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 993.768, 0, 0, 1); }
|
||||
68.97% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.903, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.903, 0, 0, 1); }
|
||||
73.56% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000.416, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000.416, 0, 0, 1); }
|
||||
88.95% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.972, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 999.972, 0, 0, 1); }
|
||||
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 1); }
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
.emoji-icon-background {
|
||||
background-size: contain;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.emoji-icon {
|
||||
background-size: contain;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 3em;
|
||||
line-height: 3em;
|
||||
z-index: 1000;
|
||||
}
|
||||
.emoji-icon:before {
|
||||
content: "\00a0";
|
||||
}
|
||||
.emoji-icon-bomb {
|
||||
background-image: url(../images/emojis/bomb.png);
|
||||
}
|
||||
.emoji-icon-bulb {
|
||||
background-image: url(../images/emojis/bulb.png);
|
||||
}
|
||||
.emoji-icon-clap {
|
||||
background-image: url(../images/emojis/clap.png);
|
||||
}
|
||||
.emoji-icon-fistbump {
|
||||
background-image: url(../images/emojis/fistbump.png);
|
||||
}
|
||||
.emoji-icon-heart {
|
||||
background-image: url(../images/emojis/heart.png);
|
||||
}
|
||||
.emoji-icon-highfive {
|
||||
background-image: url(../images/emojis/highfive.png);
|
||||
}
|
||||
|
||||
.emoji-icon-perfect {
|
||||
background-image: url(../images/emojis/perfect.png);
|
||||
}
|
||||
|
||||
.emoji-icon-sleep {
|
||||
background-image: url(../images/emojis/sleep.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley1 {
|
||||
background-image: url(../images/emojis/smiley1.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley2 {
|
||||
background-image: url(../images/emojis/smiley2.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley3 {
|
||||
background-image: url(../images/emojis/smiley3.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley4 {
|
||||
background-image: url(../images/emojis/smiley4.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley5 {
|
||||
background-image: url(../images/emojis/smiley5.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley6 {
|
||||
background-image: url(../images/emojis/smiley6.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley7 {
|
||||
background-image: url(../images/emojis/smiley7.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley8 {
|
||||
background-image: url(../images/emojis/smiley8.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley9 {
|
||||
background-image: url(../images/emojis/smiley9.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley10 {
|
||||
background-image: url(../images/emojis/smiley10.png);
|
||||
}
|
||||
|
||||
.emoji-icon-smiley11 {
|
||||
background-image: url(../images/emojis/smiley11.png);
|
||||
}
|
||||
|
||||
.emoji-icon-star {
|
||||
background-image: url(../images/emojis/star.png);
|
||||
}
|
||||
|
||||
.emoji-icon-thumbsdown {
|
||||
background-image: url(../images/emojis/thumbsdown.png);
|
||||
}
|
||||
|
||||
.emoji-icon-thumbsup {
|
||||
background-image: url(../images/emojis/thumbsup.png);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
.reactions-dialog {
|
||||
.reactions-dialog-title {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.reactions-dialog-contents {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding: 10px;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.reactions-dialog-cell {
|
||||
display: inline;
|
||||
height: 40px;
|
||||
margin: 10px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
|
@ -517,6 +517,14 @@
|
|||
width: auto;
|
||||
}
|
||||
|
||||
.emotionsCanvas {
|
||||
bottom: 0;
|
||||
height: 50%;
|
||||
max-height: 200px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#videoNotAvailableScreen {
|
||||
text-align: center;
|
||||
#avatarContainer {
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
@import 'flag-icon';
|
||||
|
||||
@import 'emoji-icons';
|
||||
@import 'emoji-animations';
|
||||
|
||||
/* Modules BEGIN */
|
||||
|
||||
@import 'dial-out';
|
||||
|
@ -75,5 +78,6 @@
|
|||
@import 'unsupported-browser/main';
|
||||
@import 'modals/invite/add-people';
|
||||
@import 'vertical_filmstrip_overrides';
|
||||
@import 'reactions';
|
||||
|
||||
/* Modules END */
|
||||
|
|
|
@ -32,14 +32,30 @@
|
|||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.speaker-stats-item__poop {
|
||||
display: inline-block;
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.speaker-stats-item__heart {
|
||||
display: inline-block;
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.speaker-stats-item__status {
|
||||
width: 5%;
|
||||
}
|
||||
.speaker-stats-item__name {
|
||||
width: 40%;
|
||||
width: 30%;
|
||||
}
|
||||
.speaker-stats-item__time {
|
||||
width: 55%;
|
||||
width: 35%;
|
||||
}
|
||||
.speaker-stats-item__poop {
|
||||
width: 15%;
|
||||
}
|
||||
.speaker-stats-item__heart {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.speaker-stats-item:nth-child(even) {
|
||||
|
@ -52,4 +68,14 @@
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.speaker-stats-item__poop {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.speaker-stats-item__heart {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 715 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 513 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 812 B |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 390 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1002 B |
After Width: | Height: | Size: 759 B |
After Width: | Height: | Size: 931 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 924 B |
After Width: | Height: | Size: 728 B |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 683 B |
After Width: | Height: | Size: 678 B |
After Width: | Height: | Size: 900 B |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 840 B |
|
@ -43,7 +43,7 @@ var interfaceConfig = {
|
|||
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup',
|
||||
|
||||
// extended toolbar
|
||||
'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip' ],
|
||||
'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'reactions', 'filmstrip' ],
|
||||
|
||||
/**
|
||||
* Main Toolbar Buttons
|
||||
|
|
|
@ -498,6 +498,7 @@
|
|||
"standardDefinition": "Standard definition",
|
||||
"qualityButtonTip": "Change received video quality"
|
||||
},
|
||||
"reactionsButtonTip": "Send a reaction",
|
||||
"dialOut": {
|
||||
"dial": "Dial",
|
||||
"dialOut": "Call a #",
|
||||
|
|
|
@ -9683,6 +9683,11 @@
|
|||
"resolved": "https://registry.npmjs.org/react-addons-text-content/-/react-addons-text-content-0.0.4.tgz",
|
||||
"integrity": "sha1-0uJZ/clR0diQbAiQIAIQjc6HkuU="
|
||||
},
|
||||
"react-animations": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-animations/-/react-animations-1.0.0.tgz",
|
||||
"integrity": "sha512-ePPpVgdKnNEXm+LP1ww5s3n0JzebBw9QdRfxRqogzeg1PDIn6kf0pmvgeTeVZQXXpGmHImkIeTiaQR1O6xjntA=="
|
||||
},
|
||||
"react-clone-referenced-element": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-clone-referenced-element/-/react-clone-referenced-element-1.0.1.tgz",
|
||||
|
|
|
@ -6,6 +6,7 @@ import React, { Component } from 'react';
|
|||
import { Watermarks } from '../../base/react';
|
||||
import { VideoQualityLabel } from '../../video-quality';
|
||||
import { RecordingLabel } from '../../recording';
|
||||
import { ReactionsCanvas } from '../../reactions';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
|
@ -79,6 +80,7 @@ export default class LargeVideo extends Component<*> {
|
|||
{ this.props.hideVideoQualityLabel
|
||||
? null : <VideoQualityLabel /> }
|
||||
<RecordingLabel />
|
||||
<ReactionsCanvas />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* The type of (redux) action which signals that a specific reaction has been
|
||||
* received by the local participant from a specific remote participant.
|
||||
*
|
||||
* {
|
||||
* type: ADD_RECEIVED_REACTION,
|
||||
* participant: Object,
|
||||
* reaction: string
|
||||
* }
|
||||
*/
|
||||
export const ADD_RECEIVED_REACTION = Symbol('ADD_RECEIVED_REACTION');
|
|
@ -0,0 +1,58 @@
|
|||
// @flow
|
||||
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { ADD_RECEIVED_REACTION } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Creates a redux action which signals that a specific reaction has been
|
||||
* received by the local participant from a specific remote participant.
|
||||
*
|
||||
* @param {string} reaction - The reaction which has been received.
|
||||
* @param {Object} participant - The remote participant who sent the reaction.
|
||||
* @returns {{
|
||||
* type: ADD_RECEIVED_REACTION,
|
||||
* participant: Object,
|
||||
* reaction: string
|
||||
* }}
|
||||
*/
|
||||
export function addReceivedReaction(reaction: string, participant: Object) {
|
||||
return {
|
||||
type: ADD_RECEIVED_REACTION,
|
||||
participant,
|
||||
reaction,
|
||||
uuid: uuid.v4()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a specific reaction of the local participant to the remote
|
||||
* participants.
|
||||
*
|
||||
* @param {string} reaction - The reaction of the local participant to send to
|
||||
* the remote participants.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function sendReaction(reaction: string) {
|
||||
// reaction = 'thumbsup', 'heart', etc
|
||||
|
||||
return (dispatch: Dispatch, getState: Function) => {
|
||||
const selectedEndpointId
|
||||
= getState()['features/base/conference']
|
||||
.conference.selectedEndpointId;
|
||||
const payload = {
|
||||
type: 'reaction',
|
||||
reaction,
|
||||
targetEndpoint: selectedEndpointId || 'target'
|
||||
};
|
||||
|
||||
getState()['features/base/conference'].conference.sendTextMessage(
|
||||
JSON.stringify({
|
||||
'jitsi-meet-muc-msg-topic': 'xxx',
|
||||
payload
|
||||
}));
|
||||
|
||||
// FIXME It's not a received reaction so rename the action creator.
|
||||
dispatch(addReceivedReaction(reaction, /* participant */ undefined));
|
||||
};
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
// Mobile friendly solution!
|
||||
// import styled, { keyframes } from 'styled-components';
|
||||
// import { merge, rollIn, zoomIn } from 'react-animations';
|
||||
|
||||
// const tadaFlip = merge(rollIn, zoomIn);
|
||||
//
|
||||
// const bounceAnimation = keyframes`${tadaFlip}`;
|
||||
//
|
||||
// const BouncySpan = styled.span`
|
||||
// animation: ${bounceAnimation} 2s;
|
||||
// animation-direction: alternate;
|
||||
// `;
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} to render an emoji icon.
|
||||
*/
|
||||
export default class EmojiIcon extends Component {
|
||||
/**
|
||||
* {@code Emoji}'s property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The css style class name.
|
||||
*/
|
||||
className: PropTypes.string,
|
||||
|
||||
/**
|
||||
* The emoji name.
|
||||
*/
|
||||
emojiName: PropTypes.string
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const iconClassName
|
||||
= `emoji-icon emoji-icon-${this.props.emojiName} animation-target`;
|
||||
|
||||
// Part of the mobile friendly solution!
|
||||
// return <BouncySpan className = { iconClassName } />;
|
||||
|
||||
return <span className = { iconClassName } />;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/* @flow */
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import EmojiIcon from './EmojiIcon';
|
||||
|
||||
/**
|
||||
* Base style for the {@code TintedView} component.
|
||||
*/
|
||||
const BASE_STYLE = {
|
||||
alignItems: 'center',
|
||||
bottom: 0,
|
||||
justifyContent: 'center',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which represents the large video (a.k.a.
|
||||
* the conference participant who is on the local stage) on Web/React.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
export default class ReactionsCanvas extends Component<*> {
|
||||
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<View style = { BASE_STYLE }>
|
||||
<EmojiIcon emojiName = 'thumbsup' />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import EmojiIcon from './EmojiIcon';
|
||||
|
||||
type Props = {
|
||||
_reactions: Array<Object>
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which represents the large video (a.k.a.
|
||||
* the conference participant who is on the local stage) on Web/React.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class ReactionsCanvas extends Component<Props> {
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const reactions = this.props._reactions;
|
||||
|
||||
if (!reactions || !reactions.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// FIXME The use of key bellow is somewhat of a hack/workaround for
|
||||
// EmojiIcon: EmojiIcon doesn't seem to restart its animation upon
|
||||
// changing its emojiName value. So the key will force a new EmojiIcon
|
||||
// instance upon different reactions.
|
||||
|
||||
return (
|
||||
<div className = 'emotionsCanvas'>
|
||||
{
|
||||
/* eslint-disable react/jsx-wrap-multilines */
|
||||
|
||||
reactions.map(
|
||||
({ reaction, uuid }) =>
|
||||
<EmojiIcon
|
||||
emojiName = { reaction }
|
||||
key = { uuid } />)
|
||||
|
||||
/* eslint-enable react/jsx-wrap-multilines */
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated ReactionsCanvas' props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _reactions: Array<Object>
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) { // eslint-disable-line no-unused-vars
|
||||
const stateFeatureReactions = state['features/reactions'];
|
||||
const receivedReactions
|
||||
= stateFeatureReactions && stateFeatureReactions.receivedReactions;
|
||||
|
||||
return {
|
||||
_reactions: receivedReactions || []
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(ReactionsCanvas);
|
|
@ -0,0 +1,135 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { sendReaction } from '../actions';
|
||||
|
||||
type Props = {
|
||||
_onSendReaction: Function,
|
||||
|
||||
onClose: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* The list of supported reactions (i.e. reaction buttons).
|
||||
*/
|
||||
const REACTIONS = [
|
||||
];
|
||||
|
||||
// FIXME Pretend there's a list of supported reactions (i.e. reaction buttons).
|
||||
REACTIONS.push('heart');
|
||||
REACTIONS.push('poop');
|
||||
REACTIONS.push('thumbsup');
|
||||
REACTIONS.push('thumbsdown');
|
||||
REACTIONS.push('bulb');
|
||||
REACTIONS.push('clap');
|
||||
REACTIONS.push('fistbump');
|
||||
REACTIONS.push('highfive');
|
||||
REACTIONS.push('perfect');
|
||||
REACTIONS.push('sleep');
|
||||
REACTIONS.push('star');
|
||||
for (let i = 1; i < 11; ++i) {
|
||||
|
||||
REACTIONS.push(`smiley${i}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the dialog in the terms of {@link ToolbarButtonWithDialog} which
|
||||
* renders the list of supported reactions (i.e. reaction buttons).
|
||||
*/
|
||||
class ReactionsDialog extends Component<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<div className = 'reactions-dialog'>
|
||||
<h3 className = 'reactions-dialog-title'>
|
||||
Reactions
|
||||
</h3>
|
||||
<div className = 'reactions-dialog-contents'>
|
||||
{ this._renderContents() }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on a reaction (button).
|
||||
*
|
||||
* @param {*} reaction - The reaction (button) which was clicked.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick(reaction) {
|
||||
// this.props.onClose();
|
||||
this.props._onSendReaction(reaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the contents of this ReactionsDialog minus its title.
|
||||
*
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
_renderContents() {
|
||||
const contents = [];
|
||||
|
||||
for (const reaction of REACTIONS) {
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
contents.push(
|
||||
<img
|
||||
className = 'reactions-dialog-cell'
|
||||
onClick = { this._onClick.bind(this, reaction) }
|
||||
src = { `images/emojis/${reaction}.png` } />
|
||||
);
|
||||
|
||||
/* eslint-enable react/jsx-no-bind */
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps dispatching of some action to React component props.
|
||||
*
|
||||
* @param {Function} dispatch - Redux action dispatcher.
|
||||
* @private
|
||||
* @returns {{
|
||||
* }}
|
||||
*/
|
||||
function _mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
/**
|
||||
* Sends a specific reaction of the local participant to the remote
|
||||
* participants.
|
||||
*
|
||||
* @param {string} reaction - The reaction of the local participant to
|
||||
* send to the remote participants.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSendReaction(reaction) {
|
||||
dispatch(sendReaction(reaction));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated ReactionsDialog's props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) { // eslint-disable-line no-unused-vars
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps, _mapDispatchToProps)(ReactionsDialog);
|
|
@ -0,0 +1,46 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { ToolbarButtonWithDialog } from '../../toolbox';
|
||||
|
||||
import ReactionsDialog from './ReactionsDialog';
|
||||
|
||||
type Props = {
|
||||
tooltipPosition: *
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@code ToolbarButton} configuration which describes how
|
||||
* {@link ReactionsToolbarButton} is to be rendered (by default).
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
const DEFAULT_BUTTON_CONFIGURATION = {
|
||||
buttonName: 'reactions',
|
||||
classNames: [ 'button', 'icon-star-full' ],
|
||||
enabled: true,
|
||||
id: 'toolbar_button_reactions',
|
||||
tooltipKey: 'reactionsButtonTip'
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the Web {@code ToolbarButton} which shows the dialog with the list
|
||||
* of supported reactions (i.e. reaction buttons).
|
||||
*/
|
||||
export default class ReactionsToolbarButton extends Component<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<ToolbarButtonWithDialog
|
||||
button = { DEFAULT_BUTTON_CONFIGURATION }
|
||||
content = { ReactionsDialog }
|
||||
tooltipPosition = { this.props.tooltipPosition } />
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default as ReactionsToolbarButton } from './ReactionsToolbarButton';
|
||||
export { default as ReactionsCanvas } from './ReactionsCanvas';
|
|
@ -0,0 +1,12 @@
|
|||
import { createStyleSheet } from '../../base/styles';
|
||||
|
||||
import { merge, tada, flip } from 'react-animations';
|
||||
|
||||
const tadaFlip = merge(tada, flip);
|
||||
|
||||
export default createStyleSheet({
|
||||
bounce: {
|
||||
animationName: tadaFlip,
|
||||
animationDuration: '10s'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
export * from './actions';
|
||||
export * from './actionTypes';
|
||||
export * from './components';
|
||||
|
||||
import './middleware';
|
||||
import './reducer';
|
|
@ -0,0 +1,47 @@
|
|||
// @flow
|
||||
|
||||
import { CONFERENCE_JOINED } from '../base/conference';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { addReceivedReaction } from './actions';
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOINED:
|
||||
return _conferenceJoined(store, next, action);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Notifies the feature app that the action {@link CONFERENCE_JOINED} is being
|
||||
* dispatched within a specific redux {@code store}.
|
||||
*
|
||||
* @param {Store} store - The redux store in which the specified {@code action}
|
||||
* is being dispatched.
|
||||
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
|
||||
* specified {@code action} to the specified {@code store}.
|
||||
* @param {Action} action - The redux action {@code CONFERENCE_JOINED} which is
|
||||
* being dispatched in the specified {@code store}.
|
||||
* @private
|
||||
* @returns {Object} The new state that is the result of the reduction of the
|
||||
* specified {@code action}.
|
||||
*/
|
||||
function _conferenceJoined({ dispatch, getState }, next, action) {
|
||||
const result = next(action);
|
||||
|
||||
getState()['features/base/conference'].conference.on(
|
||||
'conference.endpoint_message_received',
|
||||
(participant, message) => {
|
||||
let payload;
|
||||
|
||||
if (message
|
||||
&& (payload = message.payload)
|
||||
&& payload.type === 'reaction') {
|
||||
dispatch(addReceivedReaction(payload.reaction, participant));
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// @flow
|
||||
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import { ADD_RECEIVED_REACTION } from './actionTypes';
|
||||
|
||||
const _INITIAL_STATE = {
|
||||
receivedReactions: []
|
||||
};
|
||||
|
||||
ReducerRegistry.register(
|
||||
'features/reactions', (state = _INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case ADD_RECEIVED_REACTION:
|
||||
return {
|
||||
...state,
|
||||
receivedReactions: [
|
||||
...state.receivedReactions,
|
||||
{
|
||||
reaction: action.reaction,
|
||||
uuid: action.uuid
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
/**
|
||||
* React component for displaying a count. For example a number of poops.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class Count extends Component {
|
||||
/**
|
||||
* TimeElapsed component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* Count
|
||||
*/
|
||||
count: PropTypes.number
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { count } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ count }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Count;
|
||||
|
|
@ -13,6 +13,7 @@ import SpeakerStatsLabels from './SpeakerStatsLabels';
|
|||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
*
|
||||
* React component for displaying a list of speaker stats.
|
||||
*
|
||||
* @extends Component
|
||||
|
@ -122,6 +123,8 @@ class SpeakerStats extends Component<*, *> {
|
|||
|
||||
const isDominantSpeaker = statsModel.isDominantSpeaker();
|
||||
const dominantSpeakerTime = statsModel.getTotalDominantSpeakerTime();
|
||||
const poopCount = statsModel.getPoopCount();
|
||||
const heartCount = statsModel.getHeartCount();
|
||||
const hasLeft = statsModel.hasLeft();
|
||||
|
||||
let displayName;
|
||||
|
@ -144,8 +147,10 @@ class SpeakerStats extends Component<*, *> {
|
|||
displayName = { displayName }
|
||||
dominantSpeakerTime = { dominantSpeakerTime }
|
||||
hasLeft = { hasLeft }
|
||||
heartCount = { heartCount }
|
||||
isDominantSpeaker = { isDominantSpeaker }
|
||||
key = { userId } />
|
||||
key = { userId }
|
||||
poopCount = { poopCount } />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import TimeElapsed from './TimeElapsed';
|
||||
import Count from './Count';
|
||||
|
||||
/**
|
||||
* React component for display an individual user's speaker stats.
|
||||
|
@ -30,10 +31,14 @@ class SpeakerStatsItem extends Component {
|
|||
*/
|
||||
hasLeft: PropTypes.bool,
|
||||
|
||||
heartCount: PropTypes.number,
|
||||
|
||||
/**
|
||||
* True if the participant is currently the dominant speaker.
|
||||
*/
|
||||
isDominantSpeaker: PropTypes.bool
|
||||
isDominantSpeaker: PropTypes.bool,
|
||||
|
||||
poopCount: PropTypes.number
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,6 +67,14 @@ class SpeakerStatsItem extends Component {
|
|||
<TimeElapsed
|
||||
time = { this.props.dominantSpeakerTime } />
|
||||
</div>
|
||||
<div className = 'speaker-stats-item__poop'>
|
||||
<Count
|
||||
count = { this.props.poopCount } />
|
||||
</div>
|
||||
<div className = 'speaker-stats-item__heart'>
|
||||
<Count
|
||||
count = { this.props.heartCount } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,12 @@ class SpeakerStatsLabels extends Component {
|
|||
<div className = 'speaker-stats-item__time'>
|
||||
{ t('speakerStats.speakerTime') }
|
||||
</div>
|
||||
<div className = 'speaker-stats-item__poop'>
|
||||
{ '💩' }
|
||||
</div>
|
||||
<div className = 'speaker-stats-item__heart'>
|
||||
{ '💖' }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { ParticipantCounter } from '../contact-list';
|
||||
import { openDeviceSelectionDialog } from '../device-selection';
|
||||
import { InfoDialogButton, openInviteDialog } from '../invite';
|
||||
import { ReactionsToolbarButton } from '../reactions';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import { VideoQualityButton } from '../video-quality';
|
||||
|
||||
|
@ -435,6 +436,10 @@ export default function getDefaultButtons() {
|
|||
tooltipKey: 'toolbar.raiseHand'
|
||||
},
|
||||
|
||||
reactions: {
|
||||
component: ReactionsToolbarButton
|
||||
},
|
||||
|
||||
/**
|
||||
* The descriptor of the recording toolbar button. Requires additional
|
||||
* initialization in the recording module.
|
||||
|
|
|
@ -25,6 +25,17 @@ export function getDefaultToolboxButtons(buttonHandlers: Object): Object {
|
|||
|
||||
if (typeof interfaceConfig !== 'undefined'
|
||||
&& interfaceConfig.TOOLBAR_BUTTONS) {
|
||||
// FIXME Force (the display of) specific toolbar buttons in order to
|
||||
// avoid the necessity to have them in interfaceConfig.
|
||||
const FORCED_TOOLBAR_BUTTONS = [
|
||||
'reactions'
|
||||
];
|
||||
|
||||
for (const forced of FORCED_TOOLBAR_BUTTONS) {
|
||||
if (interfaceConfig.TOOLBAR_BUTTONS.indexOf(forced) === -1) {
|
||||
interfaceConfig.TOOLBAR_BUTTONS.push(forced);
|
||||
}
|
||||
}
|
||||
|
||||
toolbarButtons
|
||||
= interfaceConfig.TOOLBAR_BUTTONS.reduce(
|
||||
|
|
|
@ -25,7 +25,7 @@ const DEFAULT_BUTTON_CONFIGURATION = {
|
|||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class VideoQualityButton extends Component {
|
||||
export default class VideoQualityButton extends Component {
|
||||
/**
|
||||
* {@code VideoQualityButton}'s property types.
|
||||
*
|
||||
|
@ -54,5 +54,3 @@ class VideoQualityButton extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoQualityButton;
|
||||
|
|
|
@ -183,7 +183,9 @@ module.exports = [
|
|||
* target, undefined; otherwise, the path to the local file to be served.
|
||||
*/
|
||||
function devServerProxyBypass({ path }) {
|
||||
if (path.startsWith('/css/') || path.startsWith('/doc/')) {
|
||||
if (path.startsWith('/css/')
|
||||
|| path.startsWith('/doc/')
|
||||
|| path.startsWith('/images/')) {
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|