update
1
build/assets/achievements/firstCommit.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><line class="cls-1" x1="71.52" y1="103.43" x2="54.95" y2="103.43"/><path class="cls-1" d="M55.24,34.05v-11.85l8.58,4.77"/><path class="cls-1" d="M65.6,54.08s-18.8-1.09-10.35-20.02v-11.85"/><path class="cls-1" d="M88.45,34.05v-11.85l-8.58,4.77s-8.69-3.59-16.04,0"/><path class="cls-1" d="M78.1,54.08s18.8-1.09,10.35-20.02v-11.85"/><path class="cls-1" d="M36.67,88.45h18.88c2.68,0,4.86,2.18,4.86,4.86s-2.18,4.86-4.86,4.86h-19.7c-5.37,0-9.72-3.16-9.72-8.53,0,0-.45-5.46,5.54-7.64-4.02-24.93,20.33-29.02,21.51-41.09"/><path class="cls-1" d="M44.28,67.56c24.52-1.91,15.26,20.84,15.26,20.84"/><path class="cls-1" d="M80.31,83.82h6.83c4.85,0,8.79,3.94,8.79,8.79v10.83h-24.4v-10.83c0-4.85,3.94-8.79,8.79-8.79Z"/><path class="cls-1" d="M90.35,84.47c1.08-.42,2.25-.64,3.47-.64h4.22c5.57,0,10.09,4.84,10.09,10.84v8.77h-24.4"/><path class="cls-1" d="M87.53,50.4c2.41,10.08-.25,26.6-1.55,33.42"/><path class="cls-1" d="M59.87,63.89l4.9,29.42c.92,3.27,5.48,5.23,6.74,5.32"/><line class="cls-1" x1="76.34" y1="84.37" x2="76.21" y2="74.01"/><line class="cls-1" x1="62.42" y1="39.69" x2="68.14" y2="40.78"/><line class="cls-1" x1="82.87" y1="39.69" x2="77.14" y2="40.78"/><line class="cls-1" x1="72.41" y1="45.95" x2="73.09" y2="45.95"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
build/assets/achievements/lastCommit.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M27.1,34.19c10.23,2.5,23.21,4,37.35,4s27.12-1.5,37.35-4"/><path class="cls-1" d="M29.13,60.51c9.77,1.19,22.01,1.9,35.32,1.9s25.56-.71,35.33-1.9"/><g><line class="cls-1" x1="26.71" y1="29.29" x2="32.25" y2="100.94"/><line class="cls-1" x1="102.18" y1="29.29" x2="96.64" y2="100.94"/></g><g><line class="cls-1" x1="36.21" y1="56.72" x2="36.21" y2="43.28"/><line class="cls-1" x1="46.92" y1="56.72" x2="46.92" y2="43.28"/><line class="cls-1" x1="52.78" y1="56.72" x2="52.78" y2="43.28"/><line class="cls-1" x1="60.18" y1="56.72" x2="60.18" y2="43.28"/><line class="cls-1" x1="65.9" y1="56.72" x2="65.9" y2="43.28"/><line class="cls-1" x1="84.7" y1="56.72" x2="84.7" y2="43.28"/><line class="cls-1" x1="92.69" y1="56.72" x2="92.69" y2="43.28"/><line class="cls-1" x1="36.21" y1="50" x2="39.66" y2="50"/><line class="cls-1" x1="36.21" y1="43.28" x2="41.56" y2="43.28"/><line class="cls-1" x1="52.78" y1="43.28" x2="60.18" y2="56.72"/><line class="cls-1" x1="84.7" y1="50" x2="92.69" y2="50"/><path class="cls-1" d="M77.98,46.64c0-1.76-1.42-3.18-3.18-3.18s-3.18,1.42-3.18,3.18,1.42,3.18,3.18,3.18"/><path class="cls-1" d="M71.62,53.17c0,1.76,1.42,3.18,3.18,3.18s3.18-1.42,3.18-3.18-1.42-3.18-3.18-3.18"/></g></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
build/assets/achievements/longTask.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><line class="cls-1" x1="50.53" y1="59.27" x2="102.69" y2="59.27"/><g><line class="cls-1" x1="26.14" y1="59.27" x2="41.58" y2="59.27"/><polyline class="cls-1" points="34.41 59.23 38.9 48.33 51.84 44.51 55.25 31.85 67.37 21.36 78.95 39.47 86.58 40.02 97.07 59.23"/><polyline class="cls-1" points="34.41 64.72 38.9 78.17 51.84 82.88 55.25 98.52 67.37 111.47 78.95 89.11 86.58 88.43 97.07 64.72"/><line class="cls-1" x1="67.37" y1="21.36" x2="62.76" y2="35.59"/><line class="cls-1" x1="74.86" y1="48.67" x2="62.76" y2="35.59"/><line class="cls-1" x1="64.81" y1="48.87" x2="74.86" y2="48.67"/><line class="cls-1" x1="57.43" y1="59.27" x2="64.81" y2="48.87"/></g></svg>
|
After Width: | Height: | Size: 903 B |
|
@ -1 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M86.47,26.74H30.06c-2.15,0-3.9,1.76-3.9,3.9V99.94c0,2.15,1.76,3.9,3.9,3.9h62.07c2.15,0,3.9-1.76,3.9-3.9V54.07"/><rect class="cls-1" x="36.7" y="82.18" width="26.55" height="10.74"/><polyline class="cls-1" points="63.83 61.1 36.7 61.1 36.7 71.83 86.47 71.83 86.47 64.61"/><polyline class="cls-1" points="72.81 40.01 36.7 40.01 36.7 50.75 64.02 50.75"/><polygon class="cls-1" points="81.4 59.73 70.27 62.66 73.39 51.53 100.52 24.98 108.53 32.99 81.4 59.73"/></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><polyline class="cls-1" points="87.62 58 87.62 49.94 73.77 49.94 59.92 49.94 59.92 61.74 66.51 61.74"/><rect class="cls-1" x="32.21" y="49.94" width="27.71" height="11.8"/><rect class="cls-1" x="46.06" y="38.14" width="27.71" height="11.8"/><rect class="cls-1" x="59.91" y="26.34" width="27.71" height="11.8"/><polyline class="cls-1" points="66.51 61.74 59.92 61.74 46.06 61.74 46.06 73.54 58.29 73.54"/><rect class="cls-1" x="73.77" y="38.14" width="13.85" height="11.8"/><rect class="cls-1" x="18.35" y="61.74" width="27.71" height="11.8"/></g><circle class="cls-1" cx="80.7" cy="80.39" r="23.43"/><circle class="cls-1" cx="80.7" cy="80.39" r="5.54"/></svg>
|
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 902 B |
|
@ -1 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M76.94,97.96h21.46c2.15,0,3.9-1.76,3.9-3.9V40.53"/><path class="cls-1" d="M80.44,20.86H36.33c-2.15,0-3.9,1.76-3.9,3.9v47.37"/><polyline class="cls-1" points="92.74 51.45 42.96 51.45 42.96 60.27 92.74 60.27 92.74 51.45"/><line class="cls-1" x1="80.44" y1="20.86" x2="102.3" y2="40.53"/><line class="cls-1" x1="32.42" y1="72.13" x2="42.96" y2="72.13"/><line class="cls-1" x1="47.05" y1="80.74" x2="42.96" y2="72.13"/><line class="cls-1" x1="47.05" y1="80.74" x2="57.91" y2="80.74"/><line class="cls-1" x1="62" y1="89.35" x2="57.91" y2="80.74"/><line class="cls-1" x1="62" y1="89.35" x2="72.85" y2="89.35"/><line class="cls-1" x1="76.94" y1="97.96" x2="72.85" y2="89.35"/><g><path class="cls-1" d="M26.53,82.13v21.93c0,2.15,1.76,3.9,3.9,3.9h40.61"/><line class="cls-1" x1="26.53" y1="82.13" x2="37.07" y2="82.13"/><line class="cls-1" x1="41.16" y1="90.74" x2="37.07" y2="82.13"/><line class="cls-1" x1="41.16" y1="90.74" x2="52.01" y2="90.74"/><line class="cls-1" x1="56.1" y1="99.35" x2="52.01" y2="90.74"/><line class="cls-1" x1="56.1" y1="99.35" x2="66.95" y2="99.35"/><line class="cls-1" x1="71.05" y1="107.96" x2="66.95" y2="99.35"/></g><path class="cls-1" d="M102.3,40.53h-18.75c-1.72,0-3.11-1.39-3.11-3.11V20.86"/><g><polyline class="cls-1" points="70.29 34.14 42.96 34.14 42.96 42.95 70.29 42.95"/><line class="cls-1" x1="70.29" y1="34.14" x2="70.29" y2="42.95"/></g><g><polyline class="cls-1" points="92.74 68.76 65.41 68.76 65.41 77.58 92.74 77.58"/><line class="cls-1" x1="92.74" y1="68.76" x2="92.74" y2="77.58"/></g></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><rect class="cls-1" x="76.64" y="85.87" width="27.71" height="11.8"/><rect class="cls-1" x="48.93" y="85.87" width="27.71" height="11.8"/><rect class="cls-1" x="90.49" y="97.67" width="13.85" height="11.8"/><rect class="cls-1" x="62.78" y="97.67" width="27.71" height="11.8"/><rect class="cls-1" x="90.49" y="74.07" width="13.85" height="11.8"/><rect class="cls-1" x="71.77" y="68.22" width="16.87" height="11.8" transform="translate(56.42 -32.47) rotate(34.68)"/><rect class="cls-1" x="74.32" y="17.8" width="16.87" height="11.8" transform="translate(28.19 -42.87) rotate(34.68)"/><rect class="cls-1" x="29.82" y="23.75" width="27.71" height="11.8" transform="translate(8.84 -10.02) rotate(14.54)"/><rect class="cls-1" x="81.79" y="44.1" width="27.71" height="11.8" transform="translate(-11.42 36.43) rotate(-20.38)"/><rect class="cls-1" x="35.08" y="97.67" width="27.71" height="11.8"/><g><path class="cls-1" d="M50.23,62.27l3.06-2.49-4.54-5.58-3.06,2.49c-4.95-3.57-11.86-3.55-16.82,.48-5.93,4.82-6.82,13.54-2,19.47s13.54,6.82,19.47,2c4.96-4.04,6.38-10.8,3.89-16.37Z"/><line class="cls-1" x1="50.98" y1="56.94" x2="53.68" y2="54.74"/><polygon class="cls-1" points="53.68 54.74 56.35 45.85 58.31 51.55 66.58 43.21 63.57 49.97 75.32 45.11 64.86 52.7 70.93 55.06 60.22 55 60.77 59.69 53.68 54.74"/></g></svg>
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.5 KiB |
1
build/assets/achievements/noCommitOnDay.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><path class="cls-1" d="M39.02,21.82v28.15c0,3.24,1.68,6.08,4.22,7.71,1.67,1.07,2.73,2.86,2.65,4.84l-1.61,41.85c0,2.21,1.79,4,4,4h0c2.21,0,4-1.79,4-4l-1.61-41.96c-.07-1.95,.96-3.72,2.58-4.8,2.48-1.64,4.12-4.45,4.12-7.64V21.82"/><line class="cls-1" x1="45.21" y1="21.82" x2="45.21" y2="43.21"/><line class="cls-1" x1="51.18" y1="21.82" x2="51.18" y2="43.21"/></g><path class="cls-1" d="M89.81,37.71c0-9.53-5.02-17.25-11.21-17.25s-11.21,7.73-11.21,17.25c0,7.01,2.72,13.04,6.63,15.73,1.85,1.27,2.65,3.37,2.54,5.61l-1.86,45.32c0,2.21,1.79,4,4,4s4-1.79,4-4l-1.98-45.44c-.1-2.2,.77-4.28,2.57-5.55,3.86-2.72,6.54-8.71,6.54-15.66Z"/></svg>
|
After Width: | Height: | Size: 873 B |
1
build/assets/achievements/renameFile.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><line class="cls-1" x1="111.34" y1="56.44" x2="89" y2="78.78"/><line class="cls-1" x1="111.34" y1="56.44" x2="89" y2="34.1"/><polyline class="cls-1" points="89 78.78 89 64.42 39.83 64.42"/><line class="cls-1" x1="89" y1="48.46" x2="89" y2="34.1"/><line class="cls-1" x1="89" y1="48.46" x2="58.44" y2="48.46"/></g><g><line class="cls-1" x1="17.49" y1="72.39" x2="39.83" y2="50.05"/><line class="cls-1" x1="17.49" y1="72.39" x2="39.83" y2="94.73"/><line class="cls-1" x1="39.83" y1="50.05" x2="39.83" y2="64.42"/><line class="cls-1" x1="39.83" y1="80.37" x2="39.83" y2="94.73"/><line class="cls-1" x1="39.83" y1="80.37" x2="70.39" y2="80.37"/></g></svg>
|
After Width: | Height: | Size: 894 B |
|
@ -1,2 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg>
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 200 B |
1
build/assets/icons/CloseFullscreen.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M22 3.41 16.71 8.7 20 12h-8V4l3.29 3.29L20.59 2zM3.41 22l5.29-5.29L12 20v-8H4l3.29 3.29L2 20.59z"></path></svg>
|
After Width: | Height: | Size: 195 B |
|
@ -1,3 +1 @@
|
|||
<svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path></svg>
|
||||
|
|
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 215 B |
1
build/assets/icons/OpenFullscreen.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M21 11V3h-8l3.29 3.29-10 10L3 13v8h8l-3.29-3.29 10-10z"></path></svg>
|
After Width: | Height: | Size: 153 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V10h16v11zm0-13H4V5h16v3z"></path></svg>
|
Before Width: | Height: | Size: 225 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V9h14v10zM5 7V5h14v2H5zm2 4h10v2H7zm0 4h7v2H7z"></path></svg>
|
Before Width: | Height: | Size: 246 B |
1
build/assets/menu/team_day.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M17 12c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm1.65 7.35L16.5 17.2V14h1v2.79l1.85 1.85-.7.71zM18 3h-3.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H6c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h6.11c-.59-.57-1.07-1.25-1.42-2H6V5h2v3h8V5h2v5.08c.71.1 1.38.31 2 .6V5c0-1.1-.9-2-2-2zm-6 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></svg>
|
After Width: | Height: | Size: 428 B |
1
build/assets/menu/team_files_ext.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zm4 18H6V4h7v5h5zm-9.18-6.95L7.4 14.46 10.94 18l5.66-5.66-1.41-1.41-4.24 4.24z"></path></svg>
|
After Width: | Height: | Size: 248 B |
1
build/assets/menu/team_files_remove.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M16.5 10V9h-2v1H12v1.5h1v4c0 .83.67 1.5 1.5 1.5h2c.83 0 1.5-.67 1.5-1.5v-4h1V10zm0 5.5h-2v-4h2zM20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2m0 12H4V6h5.17l2 2H20z"></path></svg>
|
After Width: | Height: | Size: 314 B |
1
build/assets/menu/team_hours.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></svg>
|
After Width: | Height: | Size: 279 B |
1
build/assets/menu/team_month.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2m0 16H5V10h14zm0-12H5V6h14zM9 14H7v-2h2zm4 0h-2v-2h2zm4 0h-2v-2h2zm-8 4H7v-2h2zm4 0h-2v-2h2zm4 0h-2v-2h2z"></path></svg>
|
After Width: | Height: | Size: 306 B |
1
build/assets/menu/team_release.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M3 14c0 1.3.84 2.4 2 2.82V20H3v2h6v-2H7v-3.18C8.16 16.4 9 15.3 9 14V6H3zm2-6h2v3H5zm0 5h2v1c0 .55-.45 1-1 1s-1-.45-1-1zm15.64-4.46-.96-.32c-.41-.14-.68-.52-.68-.95V3c0-.55-.45-1-1-1h-3c-.55 0-1 .45-1 1v4.28c0 .43-.27.81-.68.95l-.96.32c-.81.28-1.36 1.04-1.36 1.9V20c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-9.56c0-.86-.55-1.62-1.36-1.9M16 4h1v1h-1zm4 16h-7v-2h7zm0-4h-7v-2h7zm0-4h-7v-1.56l.95-.32C15.18 9.72 16 8.57 16 7.28V7h1v.28c0 1.29.82 2.44 2.05 2.85l.95.31z"></path></svg>
|
After Width: | Height: | Size: 553 B |
1
build/assets/menu/team_tasks.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M5 5h2v3h10V5h2v5h2V5c0-1.1-.9-2-2-2h-4.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h6v-2H5zm7-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1"></path><path d="M21 11.5 15.51 17l-3.01-3-1.5 1.5 4.51 4.5 6.99-7z"></path></svg>
|
After Width: | Height: | Size: 340 B |
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M17 12c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm1.65 7.35L16.5 17.2V14h1v2.79l1.85 1.85-.7.71zM18 3h-3.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H6c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h6.11c-.59-.57-1.07-1.25-1.42-2H6V5h2v3h8V5h2v5.08c.71.1 1.38.31 2 .6V5c0-1.1-.9-2-2-2zm-6 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M7 11h2v2H7zm14-5v14c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2l.01-14c0-1.1.88-2 1.99-2h1V2h2v2h8V2h2v2h1c1.1 0 2 .9 2 2M5 8h14V6H5zm14 12V10H5v10zm-4-7h2v-2h-2zm-4 0h2v-2h-2z"></path></svg>
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 313 B |
Before Width: | Height: | Size: 660 B After Width: | Height: | Size: 660 B |
1
build/assets/recommendations/info.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#58866B"><path d="M22.65 34h3V22h-3ZM24 18.3q.7 0 1.175-.45.475-.45.475-1.15t-.475-1.2Q24.7 15 24 15q-.7 0-1.175.5-.475.5-.475 1.2t.475 1.15q.475.45 1.175.45ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 23.95q0-4.1 1.575-7.75 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24.05 4q4.1 0 7.75 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm.05-3q7.05 0 12-4.975T41 23.95q0-7.05-4.95-12T24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24.05 41ZM24 24Z"/></svg>
|
After Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 893 B After Width: | Height: | Size: 893 B |
Before Width: | Height: | Size: 9.9 KiB |
1
public/assets/achievements/firstCommit.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><line class="cls-1" x1="71.52" y1="103.43" x2="54.95" y2="103.43"/><path class="cls-1" d="M55.24,34.05v-11.85l8.58,4.77"/><path class="cls-1" d="M65.6,54.08s-18.8-1.09-10.35-20.02v-11.85"/><path class="cls-1" d="M88.45,34.05v-11.85l-8.58,4.77s-8.69-3.59-16.04,0"/><path class="cls-1" d="M78.1,54.08s18.8-1.09,10.35-20.02v-11.85"/><path class="cls-1" d="M36.67,88.45h18.88c2.68,0,4.86,2.18,4.86,4.86s-2.18,4.86-4.86,4.86h-19.7c-5.37,0-9.72-3.16-9.72-8.53,0,0-.45-5.46,5.54-7.64-4.02-24.93,20.33-29.02,21.51-41.09"/><path class="cls-1" d="M44.28,67.56c24.52-1.91,15.26,20.84,15.26,20.84"/><path class="cls-1" d="M80.31,83.82h6.83c4.85,0,8.79,3.94,8.79,8.79v10.83h-24.4v-10.83c0-4.85,3.94-8.79,8.79-8.79Z"/><path class="cls-1" d="M90.35,84.47c1.08-.42,2.25-.64,3.47-.64h4.22c5.57,0,10.09,4.84,10.09,10.84v8.77h-24.4"/><path class="cls-1" d="M87.53,50.4c2.41,10.08-.25,26.6-1.55,33.42"/><path class="cls-1" d="M59.87,63.89l4.9,29.42c.92,3.27,5.48,5.23,6.74,5.32"/><line class="cls-1" x1="76.34" y1="84.37" x2="76.21" y2="74.01"/><line class="cls-1" x1="62.42" y1="39.69" x2="68.14" y2="40.78"/><line class="cls-1" x1="82.87" y1="39.69" x2="77.14" y2="40.78"/><line class="cls-1" x1="72.41" y1="45.95" x2="73.09" y2="45.95"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
public/assets/achievements/lastCommit.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M27.1,34.19c10.23,2.5,23.21,4,37.35,4s27.12-1.5,37.35-4"/><path class="cls-1" d="M29.13,60.51c9.77,1.19,22.01,1.9,35.32,1.9s25.56-.71,35.33-1.9"/><g><line class="cls-1" x1="26.71" y1="29.29" x2="32.25" y2="100.94"/><line class="cls-1" x1="102.18" y1="29.29" x2="96.64" y2="100.94"/></g><g><line class="cls-1" x1="36.21" y1="56.72" x2="36.21" y2="43.28"/><line class="cls-1" x1="46.92" y1="56.72" x2="46.92" y2="43.28"/><line class="cls-1" x1="52.78" y1="56.72" x2="52.78" y2="43.28"/><line class="cls-1" x1="60.18" y1="56.72" x2="60.18" y2="43.28"/><line class="cls-1" x1="65.9" y1="56.72" x2="65.9" y2="43.28"/><line class="cls-1" x1="84.7" y1="56.72" x2="84.7" y2="43.28"/><line class="cls-1" x1="92.69" y1="56.72" x2="92.69" y2="43.28"/><line class="cls-1" x1="36.21" y1="50" x2="39.66" y2="50"/><line class="cls-1" x1="36.21" y1="43.28" x2="41.56" y2="43.28"/><line class="cls-1" x1="52.78" y1="43.28" x2="60.18" y2="56.72"/><line class="cls-1" x1="84.7" y1="50" x2="92.69" y2="50"/><path class="cls-1" d="M77.98,46.64c0-1.76-1.42-3.18-3.18-3.18s-3.18,1.42-3.18,3.18,1.42,3.18,3.18,3.18"/><path class="cls-1" d="M71.62,53.17c0,1.76,1.42,3.18,3.18,3.18s3.18-1.42,3.18-3.18-1.42-3.18-3.18-3.18"/></g></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
public/assets/achievements/longTask.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><line class="cls-1" x1="50.53" y1="59.27" x2="102.69" y2="59.27"/><g><line class="cls-1" x1="26.14" y1="59.27" x2="41.58" y2="59.27"/><polyline class="cls-1" points="34.41 59.23 38.9 48.33 51.84 44.51 55.25 31.85 67.37 21.36 78.95 39.47 86.58 40.02 97.07 59.23"/><polyline class="cls-1" points="34.41 64.72 38.9 78.17 51.84 82.88 55.25 98.52 67.37 111.47 78.95 89.11 86.58 88.43 97.07 64.72"/><line class="cls-1" x1="67.37" y1="21.36" x2="62.76" y2="35.59"/><line class="cls-1" x1="74.86" y1="48.67" x2="62.76" y2="35.59"/><line class="cls-1" x1="64.81" y1="48.87" x2="74.86" y2="48.67"/><line class="cls-1" x1="57.43" y1="59.27" x2="64.81" y2="48.87"/></g></svg>
|
After Width: | Height: | Size: 903 B |
|
@ -1 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M86.47,26.74H30.06c-2.15,0-3.9,1.76-3.9,3.9V99.94c0,2.15,1.76,3.9,3.9,3.9h62.07c2.15,0,3.9-1.76,3.9-3.9V54.07"/><rect class="cls-1" x="36.7" y="82.18" width="26.55" height="10.74"/><polyline class="cls-1" points="63.83 61.1 36.7 61.1 36.7 71.83 86.47 71.83 86.47 64.61"/><polyline class="cls-1" points="72.81 40.01 36.7 40.01 36.7 50.75 64.02 50.75"/><polygon class="cls-1" points="81.4 59.73 70.27 62.66 73.39 51.53 100.52 24.98 108.53 32.99 81.4 59.73"/></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><polyline class="cls-1" points="87.62 58 87.62 49.94 73.77 49.94 59.92 49.94 59.92 61.74 66.51 61.74"/><rect class="cls-1" x="32.21" y="49.94" width="27.71" height="11.8"/><rect class="cls-1" x="46.06" y="38.14" width="27.71" height="11.8"/><rect class="cls-1" x="59.91" y="26.34" width="27.71" height="11.8"/><polyline class="cls-1" points="66.51 61.74 59.92 61.74 46.06 61.74 46.06 73.54 58.29 73.54"/><rect class="cls-1" x="73.77" y="38.14" width="13.85" height="11.8"/><rect class="cls-1" x="18.35" y="61.74" width="27.71" height="11.8"/></g><circle class="cls-1" cx="80.7" cy="80.39" r="23.43"/><circle class="cls-1" cx="80.7" cy="80.39" r="5.54"/></svg>
|
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 902 B |
|
@ -1 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><path class="cls-1" d="M76.94,97.96h21.46c2.15,0,3.9-1.76,3.9-3.9V40.53"/><path class="cls-1" d="M80.44,20.86H36.33c-2.15,0-3.9,1.76-3.9,3.9v47.37"/><polyline class="cls-1" points="92.74 51.45 42.96 51.45 42.96 60.27 92.74 60.27 92.74 51.45"/><line class="cls-1" x1="80.44" y1="20.86" x2="102.3" y2="40.53"/><line class="cls-1" x1="32.42" y1="72.13" x2="42.96" y2="72.13"/><line class="cls-1" x1="47.05" y1="80.74" x2="42.96" y2="72.13"/><line class="cls-1" x1="47.05" y1="80.74" x2="57.91" y2="80.74"/><line class="cls-1" x1="62" y1="89.35" x2="57.91" y2="80.74"/><line class="cls-1" x1="62" y1="89.35" x2="72.85" y2="89.35"/><line class="cls-1" x1="76.94" y1="97.96" x2="72.85" y2="89.35"/><g><path class="cls-1" d="M26.53,82.13v21.93c0,2.15,1.76,3.9,3.9,3.9h40.61"/><line class="cls-1" x1="26.53" y1="82.13" x2="37.07" y2="82.13"/><line class="cls-1" x1="41.16" y1="90.74" x2="37.07" y2="82.13"/><line class="cls-1" x1="41.16" y1="90.74" x2="52.01" y2="90.74"/><line class="cls-1" x1="56.1" y1="99.35" x2="52.01" y2="90.74"/><line class="cls-1" x1="56.1" y1="99.35" x2="66.95" y2="99.35"/><line class="cls-1" x1="71.05" y1="107.96" x2="66.95" y2="99.35"/></g><path class="cls-1" d="M102.3,40.53h-18.75c-1.72,0-3.11-1.39-3.11-3.11V20.86"/><g><polyline class="cls-1" points="70.29 34.14 42.96 34.14 42.96 42.95 70.29 42.95"/><line class="cls-1" x1="70.29" y1="34.14" x2="70.29" y2="42.95"/></g><g><polyline class="cls-1" points="92.74 68.76 65.41 68.76 65.41 77.58 92.74 77.58"/><line class="cls-1" x1="92.74" y1="68.76" x2="92.74" y2="77.58"/></g></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><rect class="cls-1" x="76.64" y="85.87" width="27.71" height="11.8"/><rect class="cls-1" x="48.93" y="85.87" width="27.71" height="11.8"/><rect class="cls-1" x="90.49" y="97.67" width="13.85" height="11.8"/><rect class="cls-1" x="62.78" y="97.67" width="27.71" height="11.8"/><rect class="cls-1" x="90.49" y="74.07" width="13.85" height="11.8"/><rect class="cls-1" x="71.77" y="68.22" width="16.87" height="11.8" transform="translate(56.42 -32.47) rotate(34.68)"/><rect class="cls-1" x="74.32" y="17.8" width="16.87" height="11.8" transform="translate(28.19 -42.87) rotate(34.68)"/><rect class="cls-1" x="29.82" y="23.75" width="27.71" height="11.8" transform="translate(8.84 -10.02) rotate(14.54)"/><rect class="cls-1" x="81.79" y="44.1" width="27.71" height="11.8" transform="translate(-11.42 36.43) rotate(-20.38)"/><rect class="cls-1" x="35.08" y="97.67" width="27.71" height="11.8"/><g><path class="cls-1" d="M50.23,62.27l3.06-2.49-4.54-5.58-3.06,2.49c-4.95-3.57-11.86-3.55-16.82,.48-5.93,4.82-6.82,13.54-2,19.47s13.54,6.82,19.47,2c4.96-4.04,6.38-10.8,3.89-16.37Z"/><line class="cls-1" x1="50.98" y1="56.94" x2="53.68" y2="54.74"/><polygon class="cls-1" points="53.68 54.74 56.35 45.85 58.31 51.55 66.58 43.21 63.57 49.97 75.32 45.11 64.86 52.7 70.93 55.06 60.22 55 60.77 59.69 53.68 54.74"/></g></svg>
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.5 KiB |
1
public/assets/achievements/noCommitOnDay.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><path class="cls-1" d="M39.02,21.82v28.15c0,3.24,1.68,6.08,4.22,7.71,1.67,1.07,2.73,2.86,2.65,4.84l-1.61,41.85c0,2.21,1.79,4,4,4h0c2.21,0,4-1.79,4-4l-1.61-41.96c-.07-1.95,.96-3.72,2.58-4.8,2.48-1.64,4.12-4.45,4.12-7.64V21.82"/><line class="cls-1" x1="45.21" y1="21.82" x2="45.21" y2="43.21"/><line class="cls-1" x1="51.18" y1="21.82" x2="51.18" y2="43.21"/></g><path class="cls-1" d="M89.81,37.71c0-9.53-5.02-17.25-11.21-17.25s-11.21,7.73-11.21,17.25c0,7.01,2.72,13.04,6.63,15.73,1.85,1.27,2.65,3.37,2.54,5.61l-1.86,45.32c0,2.21,1.79,4,4,4s4-1.79,4-4l-1.98-45.44c-.1-2.2,.77-4.28,2.57-5.55,3.86-2.72,6.54-8.71,6.54-15.66Z"/></svg>
|
After Width: | Height: | Size: 873 B |
1
public/assets/achievements/renameFile.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128.83 128.83"><defs><style>.cls-1{fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.93px;}</style></defs><g><line class="cls-1" x1="111.34" y1="56.44" x2="89" y2="78.78"/><line class="cls-1" x1="111.34" y1="56.44" x2="89" y2="34.1"/><polyline class="cls-1" points="89 78.78 89 64.42 39.83 64.42"/><line class="cls-1" x1="89" y1="48.46" x2="89" y2="34.1"/><line class="cls-1" x1="89" y1="48.46" x2="58.44" y2="48.46"/></g><g><line class="cls-1" x1="17.49" y1="72.39" x2="39.83" y2="50.05"/><line class="cls-1" x1="17.49" y1="72.39" x2="39.83" y2="94.73"/><line class="cls-1" x1="39.83" y1="50.05" x2="39.83" y2="64.42"/><line class="cls-1" x1="39.83" y1="80.37" x2="39.83" y2="94.73"/><line class="cls-1" x1="39.83" y1="80.37" x2="70.39" y2="80.37"/></g></svg>
|
After Width: | Height: | Size: 894 B |
|
@ -1,2 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg>
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 200 B |
1
public/assets/icons/CloseFullscreen.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M22 3.41 16.71 8.7 20 12h-8V4l3.29 3.29L20.59 2zM3.41 22l5.29-5.29L12 20v-8H4l3.29 3.29L2 20.59z"></path></svg>
|
After Width: | Height: | Size: 195 B |
|
@ -1,3 +1 @@
|
|||
<svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path></svg>
|
||||
|
|
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 215 B |
1
public/assets/icons/OpenFullscreen.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M21 11V3h-8l3.29 3.29-10 10L3 13v8h8l-3.29-3.29 10-10z"></path></svg>
|
After Width: | Height: | Size: 153 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V10h16v11zm0-13H4V5h16v3z"></path></svg>
|
Before Width: | Height: | Size: 225 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V9h14v10zM5 7V5h14v2H5zm2 4h10v2H7zm0 4h7v2H7z"></path></svg>
|
Before Width: | Height: | Size: 246 B |
1
public/assets/menu/team_day.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M17 12c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm1.65 7.35L16.5 17.2V14h1v2.79l1.85 1.85-.7.71zM18 3h-3.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H6c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h6.11c-.59-.57-1.07-1.25-1.42-2H6V5h2v3h8V5h2v5.08c.71.1 1.38.31 2 .6V5c0-1.1-.9-2-2-2zm-6 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></svg>
|
After Width: | Height: | Size: 428 B |
1
public/assets/menu/team_files_ext.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zm4 18H6V4h7v5h5zm-9.18-6.95L7.4 14.46 10.94 18l5.66-5.66-1.41-1.41-4.24 4.24z"></path></svg>
|
After Width: | Height: | Size: 248 B |
1
public/assets/menu/team_files_remove.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M16.5 10V9h-2v1H12v1.5h1v4c0 .83.67 1.5 1.5 1.5h2c.83 0 1.5-.67 1.5-1.5v-4h1V10zm0 5.5h-2v-4h2zM20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2m0 12H4V6h5.17l2 2H20z"></path></svg>
|
After Width: | Height: | Size: 314 B |
1
public/assets/menu/team_hours.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></svg>
|
After Width: | Height: | Size: 279 B |
1
public/assets/menu/team_month.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2m0 16H5V10h14zm0-12H5V6h14zM9 14H7v-2h2zm4 0h-2v-2h2zm4 0h-2v-2h2zm-8 4H7v-2h2zm4 0h-2v-2h2zm4 0h-2v-2h2z"></path></svg>
|
After Width: | Height: | Size: 306 B |
1
public/assets/menu/team_release.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M3 14c0 1.3.84 2.4 2 2.82V20H3v2h6v-2H7v-3.18C8.16 16.4 9 15.3 9 14V6H3zm2-6h2v3H5zm0 5h2v1c0 .55-.45 1-1 1s-1-.45-1-1zm15.64-4.46-.96-.32c-.41-.14-.68-.52-.68-.95V3c0-.55-.45-1-1-1h-3c-.55 0-1 .45-1 1v4.28c0 .43-.27.81-.68.95l-.96.32c-.81.28-1.36 1.04-1.36 1.9V20c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-9.56c0-.86-.55-1.62-1.36-1.9M16 4h1v1h-1zm4 16h-7v-2h7zm0-4h-7v-2h7zm0-4h-7v-1.56l.95-.32C15.18 9.72 16 8.57 16 7.28V7h1v.28c0 1.29.82 2.44 2.05 2.85l.95.31z"></path></svg>
|
After Width: | Height: | Size: 553 B |
1
public/assets/menu/team_tasks.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M5 5h2v3h10V5h2v5h2V5c0-1.1-.9-2-2-2h-4.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h6v-2H5zm7-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1"></path><path d="M21 11.5 15.51 17l-3.01-3-1.5 1.5 4.51 4.5 6.99-7z"></path></svg>
|
After Width: | Height: | Size: 340 B |
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M17 12c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm1.65 7.35L16.5 17.2V14h1v2.79l1.85 1.85-.7.71zM18 3h-3.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H6c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h6.11c-.59-.57-1.07-1.25-1.42-2H6V5h2v3h8V5h2v5.08c.71.1 1.38.31 2 .6V5c0-1.1-.9-2-2-2zm-6 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M7 11h2v2H7zm14-5v14c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2l.01-14c0-1.1.88-2 1.99-2h1V2h2v2h8V2h2v2h1c1.1 0 2 .9 2 2M5 8h14V6H5zm14 12V10H5v10zm-4-7h2v-2h-2zm-4 0h2v-2h-2z"></path></svg>
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 313 B |
Before Width: | Height: | Size: 660 B After Width: | Height: | Size: 660 B |
1
public/assets/recommendations/info.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#58866B"><path d="M22.65 34h3V22h-3ZM24 18.3q.7 0 1.175-.45.475-.45.475-1.15t-.475-1.2Q24.7 15 24 15q-.7 0-1.175.5-.475.5-.475 1.2t.475 1.15q.475.45 1.175.45ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 23.95q0-4.1 1.575-7.75 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24.05 4q4.1 0 7.75 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm.05-3q7.05 0 12-4.975T41 23.95q0-7.05-4.95-12T24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24.05 41ZM24 24Z"/></svg>
|
After Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 893 B After Width: | Height: | Size: 893 B |
|
@ -19,7 +19,6 @@
|
|||
--border-radius-m: 8px;
|
||||
--border-radius-l: 12px;
|
||||
|
||||
|
||||
--color-first: #4162B5;
|
||||
--color-second: #ED675F;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
|
||||
import style from '../style/index.module.scss';
|
||||
import style from '../style/map.module.scss';
|
||||
import { getRandom } from '../helpers/level';
|
||||
|
||||
interface IBlockProps {
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { getRandomLevel } from '../helpers/level';
|
||||
import Blocks from './Blocks';
|
||||
|
||||
import style from '../style/index.module.scss';
|
||||
import style from '../style/map.module.scss';
|
||||
|
||||
function getCitySize(percent: number): [number, number] {
|
||||
if (percent > 70) return [20, 20];
|
||||
|
|
|
@ -1,27 +1,78 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import IHashMap from 'ts/interfaces/HashMap';
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import Description from 'ts/components/Description';
|
||||
import ShowSymbol from 'ts/components/ShowSymbol';
|
||||
import { shuffle } from 'ts/helpers/random';
|
||||
|
||||
import CityMap from './components/CityMap';
|
||||
import style from './style/index.module.scss';
|
||||
import style from './style/wrapper.module.scss';
|
||||
|
||||
interface ICityBuilderProps {
|
||||
interface IValue {
|
||||
title: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
function CityBuilder({}: ICityBuilderProps): React.ReactElement | null {
|
||||
const [percent, setPercent] = useState<number>(5);
|
||||
function getTotal(valuesByKey: IHashMap<number>): number {
|
||||
return Object.values(valuesByKey || {})
|
||||
.reduce((sum: number, value: number) => sum + value, 0);
|
||||
}
|
||||
|
||||
function getRandomList(valuesByKey: IHashMap<number>): IValue[] {
|
||||
const list = Object.entries(valuesByKey || {})
|
||||
.map(([title, value]: any) => ({ title, value }));
|
||||
return shuffle(list);
|
||||
}
|
||||
|
||||
interface ICityBuilderProps {
|
||||
valuesByTitle: IHashMap<number>;
|
||||
}
|
||||
|
||||
function CityBuilder({
|
||||
valuesByTitle,
|
||||
}: ICityBuilderProps): React.ReactElement | null {
|
||||
const [list, setList] = useState<IValue[]>([]);
|
||||
const [selectedIndex, setSelectedIndex] = useState<number>(0);
|
||||
const [total, setTotal] = useState<number>(100);
|
||||
const lastIndex = list.length - 1;
|
||||
|
||||
useEffect(() => {
|
||||
setTotal(getTotal(valuesByTitle));
|
||||
setList(getRandomList(valuesByTitle));
|
||||
}, [valuesByTitle]);
|
||||
|
||||
if (!list.length) return null;
|
||||
|
||||
const selected = list[selectedIndex];
|
||||
const percent = Math.ceil(((selected.value || 0) * 100) / total);
|
||||
|
||||
return (
|
||||
<>
|
||||
<UiKitButton
|
||||
className={style.races_button}
|
||||
onClick={() => {
|
||||
setPercent(Math.random() * 100);
|
||||
}}
|
||||
>
|
||||
rand
|
||||
</UiKitButton>
|
||||
<CityMap percent={percent} />
|
||||
<ShowSymbol
|
||||
text={selected.title}
|
||||
length={20}
|
||||
/>
|
||||
<Description
|
||||
text={`Сейчас в проекте есть ${selected.value || 0} файлов созданных этим пользователем. Это примерно ${percent}% от всех файлов в проекте.`}
|
||||
/>
|
||||
<div className={style.city_builder_control}>
|
||||
<UiKitButton
|
||||
disabled={!selectedIndex}
|
||||
className={style.city_builder_control_prev}
|
||||
onClick={() => {
|
||||
setSelectedIndex(selectedIndex - 1);
|
||||
}}
|
||||
/>
|
||||
<UiKitButton
|
||||
disabled={selectedIndex === lastIndex}
|
||||
className={style.city_builder_control_next}
|
||||
onClick={() => {
|
||||
setSelectedIndex(selectedIndex + 1);
|
||||
}}
|
||||
/>
|
||||
<CityMap percent={percent} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
35
src/ts/components/CityBuilder/style/wrapper.module.scss
Normal file
|
@ -0,0 +1,35 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.city_builder_control {
|
||||
position: relative;
|
||||
margin: 0 0 var(--space-xxl);
|
||||
user-select: none;
|
||||
background-color: var(--color-13);
|
||||
|
||||
&_prev,
|
||||
&_next {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
display: block;
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&_prev {
|
||||
left: 0;
|
||||
right: 30%;
|
||||
}
|
||||
|
||||
&_next {
|
||||
left: 70%;
|
||||
right: 100%;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,19 @@
|
|||
margin-left: var(--space-l);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&_full_screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
|
||||
padding: var(--space-xxl);
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
|
|
@ -5,8 +5,9 @@ import { useTranslation } from 'react-i18next';
|
|||
import ISort from 'ts/interfaces/Sort';
|
||||
import Table from 'ts/components/Table';
|
||||
import Cards from 'ts/components/Cards';
|
||||
import { downloadExcel } from 'ts/helpers/File';
|
||||
import viewSettings from 'ts/store/ViewSettings';
|
||||
import globalScroll from 'ts/helpers/globalScroll';
|
||||
import { downloadExcel } from 'ts/helpers/File';
|
||||
import isMobile from 'ts/helpers/isMobile';
|
||||
|
||||
import style from './index.module.scss';
|
||||
|
@ -40,6 +41,7 @@ function DataView({
|
|||
const urlParams = useParams<any>();
|
||||
const defaultType = viewSettings.getItem(urlParams, isMobile ? 'cards' : 'table');
|
||||
const [localType, setType] = useState<string>(type || defaultType);
|
||||
const [fullSize, setFullSize] = useState<boolean>(false);
|
||||
|
||||
if (!rows || !rows.length) return null;
|
||||
|
||||
|
@ -48,11 +50,13 @@ function DataView({
|
|||
cards: './assets/icons/Table.svg',
|
||||
}[localType];
|
||||
|
||||
const title = {
|
||||
const titleForType = {
|
||||
table: 'Отобразить карточками',
|
||||
cards: 'Отобразить таблицой',
|
||||
}[localType];
|
||||
|
||||
const fullSizeClass = fullSize ? style.data_view_full_screen : '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ position: 'relative' }}>
|
||||
|
@ -68,9 +72,24 @@ function DataView({
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
{false && !isMobile && (
|
||||
<img
|
||||
title={'Развернуть'}
|
||||
src="./assets/icons/OpenFullscreen.svg"
|
||||
className={style.data_view_icon}
|
||||
onClick={() => {
|
||||
if (fullSize) {
|
||||
globalScroll.off();
|
||||
} else {
|
||||
globalScroll.on();
|
||||
}
|
||||
setFullSize(!fullSize);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!isMobile && (
|
||||
<img
|
||||
title={title}
|
||||
title={titleForType}
|
||||
src={icon}
|
||||
className={style.data_view_icon}
|
||||
onClick={() => {
|
||||
|
@ -84,7 +103,10 @@ function DataView({
|
|||
</div>
|
||||
|
||||
{localType === 'table' && (
|
||||
<PageWrapper template="table">
|
||||
<PageWrapper
|
||||
template="table"
|
||||
className={fullSizeClass}
|
||||
>
|
||||
<Table
|
||||
rows={rows}
|
||||
sort={sort}
|
||||
|
|
|
@ -6,14 +6,15 @@ import style from './index.module.scss';
|
|||
interface IExternalLinkProps {
|
||||
link: string,
|
||||
text: string,
|
||||
className?: string,
|
||||
}
|
||||
|
||||
function ExternalLink({ link, text }: IExternalLinkProps) {
|
||||
function ExternalLink({ link, text, className }: IExternalLinkProps) {
|
||||
return (
|
||||
<Link
|
||||
to={link}
|
||||
target="_blank"
|
||||
className={style.external_link}
|
||||
className={`${style.external_link} ${className || ''}`}
|
||||
>
|
||||
{text}
|
||||
</Link>
|
||||
|
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import ICommit from 'ts/interfaces/Commit';
|
||||
import ExternalLink from 'ts/components/ExternalLink';
|
||||
import userSettings from 'ts/store/UserSettings';
|
||||
import { getDate } from 'ts/helpers/formatter';
|
||||
import dataGrip from 'ts/helpers/DataGrip';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
@ -23,19 +24,24 @@ function GetItem({ commit, mode }: IGetItemProps) {
|
|||
<div className={style.get_list}>
|
||||
<div className={style.get_list_title}>
|
||||
<ExternalLink
|
||||
link={`${userSettings?.settings?.linksPrefix?.task || '/'}${commit.task}`}
|
||||
text={commit.task}
|
||||
link={`${userSettings?.settings?.linksPrefix?.task || '/'}${commit.task}`}
|
||||
className={style.get_list_task}
|
||||
/>
|
||||
{prId && mode !== 'print' && (
|
||||
<ExternalLink
|
||||
text="pull request"
|
||||
link={`${userSettings?.settings?.linksPrefix?.pr || '/'}${prId}`}
|
||||
text="PR"
|
||||
className={style.get_list_pr}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${style.get_list_icon} ${className}`}>
|
||||
{commit.taskNumber}
|
||||
</div>
|
||||
<div className={style.get_list_date}>
|
||||
{getDate(commit.date)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,37 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.get_list_container {
|
||||
margin: 12px 0 24px 0;
|
||||
}
|
||||
|
||||
.get_list {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0 var(--space-sm) var(--space-sm) 0;
|
||||
min-width: 140px;
|
||||
padding: var(--space-m) var(--space-m) var(--space-s);
|
||||
margin: 0 0 var(--space-sm) 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
|
||||
&:last-child {
|
||||
margin: 0 var(--space-sm) 0 0;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius-s);
|
||||
background-color: #F5F7F9;
|
||||
|
||||
&_container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
padding: var(--space-m) var(--space-m) 0;
|
||||
margin: var(--space-m) 0 var(--space-xxl) 0;
|
||||
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius-s);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
&_title {
|
||||
position: relative;
|
||||
font-size: var(--font-s);
|
||||
display: block;
|
||||
min-height: 87px;
|
||||
margin: 0 0 var(--space-s) 0;
|
||||
padding: var(--space-xxl) var(--space-s);
|
||||
|
||||
|
@ -66,6 +78,7 @@
|
|||
border-radius: 32px;
|
||||
letter-spacing: 2px;
|
||||
|
||||
border: 2px dotted white;
|
||||
color: var(--color-black);
|
||||
background-color: var(--color-border);
|
||||
}
|
||||
|
@ -73,5 +86,26 @@
|
|||
&_big_number {
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
&_task {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&_pr {
|
||||
display: block;
|
||||
margin: var(--space-m) auto 0;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
|
||||
&_date {
|
||||
font-size: var(--font-s);
|
||||
margin: var(--space-m) auto 0;
|
||||
padding: var(--space-s) 0 0 0;
|
||||
|
||||
text-align: center;
|
||||
color: var(--color-grey);
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { ReactNode, useEffect } from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
|
||||
import isMobile from 'ts/helpers/isMobile';
|
||||
import globalScroll from 'ts/helpers/globalScroll';
|
||||
|
||||
import Header from './components/Header';
|
||||
import Body from './components/Body';
|
||||
|
@ -21,13 +22,7 @@ function Modal({
|
|||
onClose,
|
||||
children,
|
||||
}: IModalProps) {
|
||||
useEffect(() => {
|
||||
const overflowY = document.body.style.overflowY;
|
||||
document.body.style.overflowY = 'hidden';
|
||||
return () => {
|
||||
document.body.style.overflowY = overflowY;
|
||||
};
|
||||
}, []);
|
||||
useEffect(globalScroll.useOnOff, []);
|
||||
|
||||
const childrenWithProps = React.Children.map(children, (child) => (React.isValidElement(child)
|
||||
? React.cloneElement(
|
||||
|
|
|
@ -4,14 +4,16 @@ import style from './index.module.scss';
|
|||
|
||||
interface IPageWrapperProps {
|
||||
children: ReactNode | string | null;
|
||||
className?: string;
|
||||
template?: 'box' | 'table';
|
||||
}
|
||||
|
||||
function PageWrapper({
|
||||
children,
|
||||
className,
|
||||
template,
|
||||
}: IPageWrapperProps) {
|
||||
const className = template
|
||||
const localClassName = template
|
||||
? `${style.main_wrapper} ${style.main_wrapper_white}`
|
||||
: `${style.main_wrapper}`;
|
||||
|
||||
|
@ -21,7 +23,7 @@ function PageWrapper({
|
|||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
className={`${localClassName} ${className || ''}`}
|
||||
style={css}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { shuffle } from './index';
|
||||
import Info from './Info';
|
||||
import style from './index.module.scss';
|
||||
|
||||
const DURATION = {
|
||||
MIN: 5,
|
||||
BASE: 10,
|
||||
};
|
||||
|
||||
const animations = [
|
||||
'ease',
|
||||
'ease-in',
|
||||
'ease-out',
|
||||
'ease-in-out',
|
||||
'linear',
|
||||
'cubic-bezier(0.1, 0.7, 1, 0.1)',
|
||||
];
|
||||
|
||||
function getRandom(max: number) {
|
||||
return Math.floor(Math.random() * (max - 0 + 1)) + 0;
|
||||
}
|
||||
|
||||
interface ITrackProps {
|
||||
title: string;
|
||||
speed: number;
|
||||
type?: string;
|
||||
canStart?: boolean;
|
||||
}
|
||||
|
||||
function Track({
|
||||
title,
|
||||
speed,
|
||||
type,
|
||||
canStart,
|
||||
}: ITrackProps): React.ReactElement | null {
|
||||
const modeIndex = getRandom(animations.length - 1);
|
||||
const [mode] = useState<string>(animations[modeIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
shuffle(animations);
|
||||
}, []);
|
||||
|
||||
if (!title) return null;
|
||||
const duration = DURATION.MIN + (DURATION.BASE * (1 - speed)) * 3;
|
||||
const classForMove = canStart ? style.races_track_animation : '';
|
||||
|
||||
return (
|
||||
<div className={`${style.races_track} ${type || ''}`}>
|
||||
{canStart && (
|
||||
<Info
|
||||
title={title}
|
||||
duration={duration}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${style.races_track_car} ${type || ''} ${classForMove || ''}`}
|
||||
style={{
|
||||
animationTimingFunction: mode,
|
||||
animationDuration: `${duration}s`,
|
||||
}}
|
||||
>
|
||||
<div className={`${style.races_track_car_title} ${type || ''}`}>
|
||||
{title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Track.defaultProps = {
|
||||
type: '',
|
||||
canStart: false,
|
||||
};
|
||||
|
||||
export default Track;
|
62
src/ts/components/Races/components/Car.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { shuffle, getRandom } from 'ts/helpers/random';
|
||||
|
||||
import style from '../styles/car.module.scss';
|
||||
|
||||
const animations = [
|
||||
'ease',
|
||||
'ease-in',
|
||||
'ease-out',
|
||||
'ease-in-out',
|
||||
'linear',
|
||||
'cubic-bezier(0.1, 0.7, 1, 0.1)',
|
||||
];
|
||||
|
||||
interface ICarProps {
|
||||
title: string;
|
||||
duration: number;
|
||||
type?: string;
|
||||
canStart?: boolean;
|
||||
}
|
||||
|
||||
function Car({
|
||||
title,
|
||||
duration,
|
||||
type,
|
||||
canStart,
|
||||
}: ICarProps): React.ReactElement | null {
|
||||
const modeIndex = getRandom(animations.length - 1);
|
||||
const [mode] = useState<string>(animations[modeIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
shuffle(animations);
|
||||
}, []);
|
||||
|
||||
const classForMove = canStart ? style.races_track_car_animation : '';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${style.races_track_car} ${type || ''} ${classForMove || ''}`}
|
||||
style={{
|
||||
animationTimingFunction: mode,
|
||||
animationDuration: `${duration}s`,
|
||||
}}
|
||||
>
|
||||
<div className={`${style.races_track_car_title} ${type || ''}`}>
|
||||
{title}
|
||||
</div>
|
||||
<img
|
||||
className={style.races_track_car_cover}
|
||||
src="./assets/games/car.png"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Car.defaultProps = {
|
||||
type: '',
|
||||
canStart: false,
|
||||
};
|
||||
|
||||
export default Car;
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
|
||||
import style from './index.module.scss';
|
||||
import style from '../styles/info.module.scss';
|
||||
|
||||
interface IInfoProps {
|
||||
title: string;
|
||||
|
@ -11,6 +11,7 @@ function Info({
|
|||
title,
|
||||
duration,
|
||||
}: IInfoProps): React.ReactElement | null {
|
||||
console.log(title);
|
||||
return (
|
||||
<div
|
||||
className={style.races_track_info}
|
||||
|
@ -18,7 +19,7 @@ function Info({
|
|||
animationDelay: `${duration + 1}s`,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
4
|
||||
</div>
|
||||
);
|
||||
}
|
52
src/ts/components/Races/components/Track.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
|
||||
import Info from './Info';
|
||||
import Car from './Car';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
||||
const DURATION = {
|
||||
MIN: 10,
|
||||
BASE: 20,
|
||||
};
|
||||
|
||||
interface ITrackProps {
|
||||
title: string;
|
||||
speed: number;
|
||||
type?: string;
|
||||
canStart?: boolean;
|
||||
}
|
||||
|
||||
function Track({
|
||||
title,
|
||||
speed,
|
||||
type,
|
||||
canStart,
|
||||
}: ITrackProps): React.ReactElement | null {
|
||||
if (!title) return null;
|
||||
const duration = DURATION.MIN + (DURATION.BASE * (1 - speed)) * 3;
|
||||
|
||||
return (
|
||||
<div className={`${style.races_track} ${type || ''}`}>
|
||||
{canStart && (
|
||||
<Info
|
||||
title={title}
|
||||
duration={duration}
|
||||
/>
|
||||
)}
|
||||
<Car
|
||||
title={title}
|
||||
duration={duration}
|
||||
type={type}
|
||||
canStart={canStart}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Track.defaultProps = {
|
||||
type: '',
|
||||
canStart: false,
|
||||
};
|
||||
|
||||
export default Track;
|
|
@ -1,106 +0,0 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.races {
|
||||
position: relative;
|
||||
margin: 0 auto var(--space-xxl);
|
||||
border: var(--space-xs) solid var(--color-border);
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
|
||||
&_track {
|
||||
position: relative;
|
||||
height: 70px;
|
||||
padding: var(--space-xxs);
|
||||
margin: 0 auto;
|
||||
|
||||
text-align: right;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background-color: var(--color-grey);
|
||||
|
||||
&_car {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 10%;
|
||||
height: 100%;
|
||||
|
||||
background-image: url('../../../assets/games/car.png');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 70%;
|
||||
|
||||
&_title {
|
||||
font-size: 12px;
|
||||
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: var(--space-xss);
|
||||
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
border: 1px solid var(--color-grey);
|
||||
border-radius: var(--border-radius-s);
|
||||
color: var(--color-black);
|
||||
background-color: var(--color-border);
|
||||
}
|
||||
}
|
||||
|
||||
&_info {
|
||||
font-size: 12px;
|
||||
|
||||
display: inline-block;
|
||||
width: 10%;
|
||||
height: 100%;
|
||||
margin: 0 12%;
|
||||
padding: var(--space-m);
|
||||
|
||||
text-align: left;
|
||||
border-radius: var(--border-radius-l);
|
||||
border: 1px solid var(--color-grey);
|
||||
color: var(--color-black);
|
||||
background-color: var(--color-border);
|
||||
|
||||
animation-name: races_track_info;
|
||||
animation-iteration-count: 1;
|
||||
animation-duration: 1s;
|
||||
animation-direction: alternate;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
&_animation {
|
||||
animation-name: races_track_car;
|
||||
animation-iteration-count: 1;
|
||||
animation-direction: alternate;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
}
|
||||
|
||||
&_button {
|
||||
position: absolute;
|
||||
top: var(--space-l);
|
||||
left: calc(50% - 100px);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes races_track_car {
|
||||
from {
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes races_track_info {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
|
@ -2,15 +2,11 @@ import React, { useState } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import { shuffle } from 'ts/helpers/random';
|
||||
|
||||
import Track from './Track';
|
||||
import style from './index.module.scss';
|
||||
import Track from './components/Track';
|
||||
|
||||
export function shuffle(items: any[]) {
|
||||
// @ts-ignore
|
||||
for (let j, x, i = items.length; i; j = parseInt(Math.random() * i), x = items[--i], items[i] = items[j], items[j] = x) {}
|
||||
return items;
|
||||
}
|
||||
import style from './styles/index.module.scss';
|
||||
|
||||
interface IRacesProps {
|
||||
tracks: {
|
||||
|
@ -25,10 +21,11 @@ function Races({
|
|||
}: IRacesProps): React.ReactElement | null {
|
||||
const { t } = useTranslation();
|
||||
const [showAnimation, setShowAnimation] = useState<boolean>(false);
|
||||
const [shuffleTracks] = useState<any>([...shuffle(tracks)]);
|
||||
|
||||
if (!tracks.length) return null;
|
||||
|
||||
const lines = shuffle(tracks).map((track: any) => {
|
||||
const lines = shuffleTracks.map((track: any) => {
|
||||
return (
|
||||
<Track
|
||||
key={track.title}
|
||||
|
|
69
src/ts/components/Races/styles/car.module.scss
Normal file
|
@ -0,0 +1,69 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.races_track_car {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 10%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
||||
&_title {
|
||||
font-size: 12px;
|
||||
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin: var(--space-xs) auto 0 auto;
|
||||
padding: var(--space-xxs) var(--space-xs);
|
||||
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
border: 1px solid var(--color-grey);
|
||||
border-radius: var(--border-radius-s);
|
||||
color: var(--color-black);
|
||||
background-color: white;
|
||||
|
||||
&:before {
|
||||
content: ' ';
|
||||
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 47%;
|
||||
|
||||
display: block;
|
||||
padding: 4px;
|
||||
transform: rotate(45deg);
|
||||
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&_cover {
|
||||
font-size: 12px;
|
||||
|
||||
display: block;
|
||||
height: 50%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&_animation {
|
||||
animation-name: races_track_car;
|
||||
animation-iteration-count: 1;
|
||||
animation-direction: alternate;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes races_track_car {
|
||||
from {
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: 90%;
|
||||
}
|
||||
}
|
33
src/ts/components/Races/styles/index.module.scss
Normal file
|
@ -0,0 +1,33 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.races {
|
||||
position: relative;
|
||||
margin: 0 auto var(--space-xxl);
|
||||
border: var(--space-xxl) solid var(--color-13);
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
user-select: none;
|
||||
|
||||
&_track {
|
||||
position: relative;
|
||||
height: 80px;
|
||||
padding: var(--space-xxs);
|
||||
margin: 0 auto;
|
||||
|
||||
text-align: right;
|
||||
border-bottom: var(--space-xxs) dashed var(--color-border);
|
||||
background-color: var(--color-grey);
|
||||
|
||||
&:first-child {
|
||||
border-top: var(--space-xxs) dashed var(--color-border);
|
||||
}
|
||||
}
|
||||
|
||||
&_button {
|
||||
position: absolute;
|
||||
top: var(--space-l);
|
||||
left: calc(50% - 100px);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
36
src/ts/components/Races/styles/info.module.scss
Normal file
|
@ -0,0 +1,36 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.races_track_info {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 5px 12%;
|
||||
padding: var(--space-s) 0;
|
||||
|
||||
text-align: center;
|
||||
border-radius: 60px;
|
||||
line-height: 40px;
|
||||
box-sizing: border-box;
|
||||
border: var(--space-xxs) solid var(--color-border);
|
||||
color: var(--color-black);
|
||||
background-color: white;
|
||||
|
||||
animation-name: races_track_info;
|
||||
animation-iteration-count: 1;
|
||||
animation-duration: 1s;
|
||||
animation-direction: alternate;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
|
||||
@keyframes races_track_info {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,16 @@ function getClassName(recommendation?: any) {
|
|||
}[type || RECOMMENDATION_TYPES.INFO] ?? style.recommendations_card_fact;
|
||||
}
|
||||
|
||||
function getImageUrl(recommendation?: any) {
|
||||
const type = recommendation?.type;
|
||||
return {
|
||||
[RECOMMENDATION_TYPES.INFO]: './assets/recommendations/info.svg',
|
||||
[RECOMMENDATION_TYPES.FACT]: './assets/recommendations/fact.svg',
|
||||
[RECOMMENDATION_TYPES.WARNING]: './assets/recommendations/warning.svg',
|
||||
[RECOMMENDATION_TYPES.ALERT]: './assets/recommendations/alert.svg',
|
||||
}[type || RECOMMENDATION_TYPES.INFO] ?? './assets/recommendations/info.svg';
|
||||
}
|
||||
|
||||
interface IRecommendationsProps {
|
||||
recommendation: any;
|
||||
onClick: Function;
|
||||
|
@ -45,7 +55,10 @@ function Card({
|
|||
onClick={isMobile ? onClick : undefined}
|
||||
>
|
||||
<h5 className={style.recommendations_card_title}>
|
||||
<span className={style.recommendations_card_icon}></span>
|
||||
<img
|
||||
className={style.recommendations_card_icon}
|
||||
src={getImageUrl(recommendation)}
|
||||
/>
|
||||
{localization.get(title, titleArgs)}
|
||||
</h5>
|
||||
<Description
|
||||
|
|
|
@ -46,14 +46,13 @@
|
|||
position: absolute;
|
||||
top: var(--space-s);
|
||||
right: var(--space-s);
|
||||
z-index: 0;
|
||||
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 100% auto;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&_button {
|
||||
|
@ -64,28 +63,24 @@
|
|||
|
||||
&_info {
|
||||
--color-temp-border: #97C2A9;
|
||||
--color-temp-icon: url('/assets/recommendations/info.svg');
|
||||
--color-temp-bg: #E3F8EC;
|
||||
--color-temp-title: #58866B;
|
||||
}
|
||||
|
||||
&_fact {
|
||||
--color-temp-border: var(--color-11);
|
||||
--color-temp-icon: url('/assets/recommendations/info.svg');
|
||||
--color-temp-bg: #EFF7FF;
|
||||
--color-temp-title: var(--color-first);
|
||||
}
|
||||
|
||||
&_warning {
|
||||
--color-temp-border: var(--color-21);
|
||||
--color-temp-icon: url('/assets/recommendations/warning.svg');
|
||||
--color-temp-bg: #FFF5F2;
|
||||
--color-temp-title: #E8B06D;
|
||||
}
|
||||
|
||||
&_error {
|
||||
--color-temp-border: var(--color-12);
|
||||
--color-temp-icon: url('/assets/recommendations/alert.svg');
|
||||
--color-temp-bg: #FFEFEE;
|
||||
--color-temp-title: #DD8B87;
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import Description from 'ts/components/Description';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants';
|
||||
|
||||
import style from '../styles/card.module.scss';
|
||||
|
||||
function getClassName(recommendation?: any) {
|
||||
const type = recommendation?.type;
|
||||
return {
|
||||
[RECOMMENDATION_TYPES.INFO]: style.recommendations_card_info,
|
||||
[RECOMMENDATION_TYPES.FACT]: style.recommendations_card_fact,
|
||||
[RECOMMENDATION_TYPES.WARNING]: style.recommendations_card_warning,
|
||||
[RECOMMENDATION_TYPES.ALERT]: style.recommendations_card_error,
|
||||
}[type || RECOMMENDATION_TYPES.INFO] ?? style.recommendations_card_fact;
|
||||
}
|
||||
|
||||
function getDescriptionText(recommendation?: any) {
|
||||
const descriptionArgs = recommendation?.arguments?.description;
|
||||
const { description } = recommendation;
|
||||
const list = Array.isArray(description)
|
||||
? description
|
||||
: [description];
|
||||
|
||||
return list.map((textId: string) => (
|
||||
localization.get(textId, descriptionArgs)
|
||||
)).join('\n');
|
||||
}
|
||||
|
||||
interface IRecommendationsProps {
|
||||
recommendation: any;
|
||||
}
|
||||
|
||||
function Card({
|
||||
recommendation,
|
||||
}: IRecommendationsProps) {
|
||||
if (!recommendation) return null;
|
||||
|
||||
const { title } = recommendation;
|
||||
let formattedTitle = title || '';
|
||||
if (Array.isArray(title)) {
|
||||
formattedTitle = title.length > 1
|
||||
? `${title[0]} +${title.length - 1}`
|
||||
: title[0];
|
||||
}
|
||||
|
||||
const className = getClassName(recommendation);
|
||||
const titleArgs = recommendation?.arguments?.title;
|
||||
const parts = getDescriptionText(recommendation).split('\n');
|
||||
const previewText = parts.shift();
|
||||
const mainText = parts.join('\n');
|
||||
|
||||
return (
|
||||
<div className={`${style.recommendations_card} ${className}`}>
|
||||
<div className={style.recommendations_card_wrapper}>
|
||||
<h5 className={style.recommendations_card_title}>
|
||||
<span className={style.recommendations_card_icon}></span>
|
||||
{localization.get(formattedTitle, titleArgs)}
|
||||
</h5>
|
||||
<Description
|
||||
style={{ color: '#12131B' }}
|
||||
text={previewText || ''}
|
||||
/>
|
||||
<div className={style.recommendations_card_shortcut}>
|
||||
<Description
|
||||
style={{ color: '#12131B' }}
|
||||
text={mainText || ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default Card;
|
|
@ -1,60 +0,0 @@
|
|||
import React, { useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
import Card from './components/Card';
|
||||
import style from './styles/index.module.scss';
|
||||
|
||||
interface IRecommendationsProps {
|
||||
recommendations: any[];
|
||||
}
|
||||
|
||||
function Recommendations({
|
||||
recommendations,
|
||||
}: IRecommendationsProps) {
|
||||
const [maxCardsOnDisplay, setMaxCardsOnDisplay] = useState<number>(5);
|
||||
const [isOpen, setOpen] = useState<boolean>(false);
|
||||
const ref = useRef() as React.MutableRefObject<HTMLDivElement>;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const width = ref?.current?.offsetWidth;
|
||||
const placeForCard = (width - 30) / (220 + 24);
|
||||
setMaxCardsOnDisplay(placeForCard);
|
||||
}, []);
|
||||
|
||||
const className = isOpen
|
||||
? style.recommendations_full
|
||||
: style.recommendations_short;
|
||||
|
||||
const children = (recommendations || [])
|
||||
.filter(item => item)
|
||||
.map((recommendation) => (
|
||||
<Card
|
||||
key={recommendation[1]}
|
||||
recommendation={recommendation}
|
||||
/>
|
||||
));
|
||||
const visibleChildren = children.slice(0, isOpen ? Infinity : maxCardsOnDisplay);
|
||||
|
||||
if (!children.length) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={className}
|
||||
>
|
||||
{isOpen ? children : visibleChildren}
|
||||
{!isOpen && children.length > maxCardsOnDisplay && (
|
||||
<div
|
||||
className={style.more}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
»
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default Recommendations;
|
|
@ -1,166 +0,0 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.recommendations {
|
||||
&_short,
|
||||
&_full {
|
||||
position: relative;
|
||||
display: block;
|
||||
max-height: 108px;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
&_full {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
&_more,
|
||||
&_card {
|
||||
display: inline-block;
|
||||
min-height: 100px;
|
||||
max-height: 100px;
|
||||
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
white-space: normal;
|
||||
|
||||
border-radius: var(--border-radius-m);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
&_more {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 30px;
|
||||
margin: 0 0 8px 0;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--color-border);
|
||||
color: #AAAAAA;
|
||||
}
|
||||
|
||||
&_card {
|
||||
position: relative;
|
||||
width: 220px;
|
||||
margin: 0 12px 16px 0;
|
||||
border-left: none;
|
||||
|
||||
&_wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
display: block;
|
||||
min-height: 100px;
|
||||
max-height: 100px;
|
||||
padding: 16px;
|
||||
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: var(--border-radius-m);
|
||||
border: 1px solid var(--color-border);
|
||||
border-left: 8px solid var(--color-border);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
&_icon {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 100% auto;
|
||||
}
|
||||
|
||||
&_info {
|
||||
--color-temp-border: #97C2A9;
|
||||
--color-temp-icon: url('/assets/recommendations/info.svg');
|
||||
--color-temp-bg: #E3F8EC;
|
||||
--color-temp-title: #58866B;
|
||||
}
|
||||
|
||||
&_fact {
|
||||
--color-temp-border: var(--color-11);
|
||||
--color-temp-icon: url('/assets/recommendations/info.svg');
|
||||
--color-temp-bg: #EFF7FF;
|
||||
--color-temp-title: var(--color-first);
|
||||
}
|
||||
|
||||
&_warning {
|
||||
--color-temp-border: var(--color-21);
|
||||
--color-temp-icon: url('/assets/recommendations/warning.svg');
|
||||
--color-temp-bg: #FFF5F2;
|
||||
--color-temp-title: #E8B06D;
|
||||
}
|
||||
|
||||
&_error {
|
||||
--color-temp-border: var(--color-12);
|
||||
--color-temp-icon: url('/assets/recommendations/alert.svg');
|
||||
--color-temp-bg: #FFEFEE;
|
||||
--color-temp-title: #DD8B87;
|
||||
}
|
||||
|
||||
&_title {
|
||||
font-weight: bold;
|
||||
font-size: var(--font-xs);
|
||||
|
||||
display: block;
|
||||
padding: 2px 0 0 24px;
|
||||
margin: 0 auto 4px auto;
|
||||
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
vertical-align: bottom;
|
||||
color: var(--color-temp-title);
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
background-color: var(--color-temp-bg);
|
||||
border-left-color: var(--color-temp-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recommendations_card:hover > .recommendations_card_wrapper {
|
||||
z-index: 2;
|
||||
width: 170%;
|
||||
max-height: 450px;
|
||||
box-shadow: 2px 2px 3px #999999;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.recommendations_card_wrapper::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.recommendations_card_wrapper::-webkit-scrollbar-thumb {
|
||||
background: #AAAAAA;
|
||||
}
|
||||
|
||||
.recommendations_title {
|
||||
color: var(--color-temp-border);
|
||||
}
|
||||
|
||||
.recommendations_card_icon {
|
||||
background-image: var(--color-temp-icon);
|
||||
}
|
||||
|
||||
.recommendations_card_shortcut {
|
||||
display: none;
|
||||
padding: 6px 0 0 0;
|
||||
margin: 6px 0 0 0;
|
||||
border-top: 1px solid var(--color-temp-border);
|
||||
}
|
||||
|
||||
.recommendations_card:hover .recommendations_card_shortcut {
|
||||
display: block;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.recommendations_short,
|
||||
.recommendations_full {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.more {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
white-space: normal;
|
||||
|
||||
cursor: pointer;
|
||||
border-radius: var(--border-radius-m);
|
||||
line-height: 100px;
|
||||
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-black);
|
||||
background-color: white;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import Title from 'ts/components/Title';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
import Recommendations from './index';
|
||||
|
||||
interface IRecommendationsWrapperProps {
|
||||
recommendations: any[];
|
||||
}
|
||||
|
||||
function RecommendationsWrapper({
|
||||
recommendations,
|
||||
}: IRecommendationsWrapperProps) {
|
||||
if (!recommendations.length) return null;
|
||||
|
||||
const title = localization.get('recommendations.title');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={title}/>
|
||||
<Recommendations recommendations={recommendations} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default RecommendationsWrapper;
|
31
src/ts/components/ShowSymbol/components/Button.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
||||
interface IButtonProps {
|
||||
children: ReactNode;
|
||||
onClick: Function;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
function Button({
|
||||
children,
|
||||
onClick,
|
||||
mode,
|
||||
}: IButtonProps): React.ReactElement | null {
|
||||
const classNameMode = {
|
||||
'table-row': style.show_symbol_s,
|
||||
}[mode || ''] || '';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${style.show_symbol} ${style.show_symbol_hide} ${classNameMode}`}
|
||||
onClick={() => onClick()}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default Button;
|
40
src/ts/components/ShowSymbol/components/OneSymbol.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
||||
interface IOneSymbolProps {
|
||||
show: boolean;
|
||||
children: ReactNode;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
function OneSymbol({
|
||||
show,
|
||||
children,
|
||||
mode,
|
||||
}: IOneSymbolProps): React.ReactElement | null {
|
||||
const [localShow, setShow] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setShow(show);
|
||||
}, [show]);
|
||||
|
||||
const className = localShow ? style.show_symbol_hide : '';
|
||||
const classNameBg = localShow ? style.show_symbol_bg_hide : '';
|
||||
const classNameMode = {
|
||||
'table-row': style.show_symbol_s,
|
||||
}[mode || ''] || '';
|
||||
|
||||
return (
|
||||
<div className={`${style.show_symbol} ${className} ${classNameMode}`}>
|
||||
{children}
|
||||
<div
|
||||
className={`${style.show_symbol_bg} ${classNameBg}`}
|
||||
onClick={() => setShow(true)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default OneSymbol;
|
71
src/ts/components/ShowSymbol/index.tsx
Normal file
|
@ -0,0 +1,71 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import OneSymbol from './components/OneSymbol';
|
||||
import Button from './components/Button';
|
||||
|
||||
import style from './styles/index.module.scss';
|
||||
|
||||
function getSymbolList(text: string, length?: number) {
|
||||
const list = (text || '').split('');
|
||||
const lastIndex = length
|
||||
? (length - 1)
|
||||
: (list.length - 1);
|
||||
|
||||
if ((list.length - 1) > lastIndex) {
|
||||
list[lastIndex] = '…';
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
interface IShowSymbolProps {
|
||||
text: string;
|
||||
length?: number;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
function ShowSymbol({
|
||||
text,
|
||||
length,
|
||||
mode,
|
||||
}: IShowSymbolProps): React.ReactElement | null {
|
||||
const [showAll, setShowAll] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setShowAll(false);
|
||||
}, [text]);
|
||||
|
||||
if (!text && !length) return null;
|
||||
|
||||
const list = getSymbolList(text, length);
|
||||
const fakeList = length ? (new Array(length)).fill(1) : null;
|
||||
const line = (fakeList || list)
|
||||
.map((symbol: string, index: number) => (
|
||||
<OneSymbol
|
||||
key={`${text}|${symbol}|${index}`}
|
||||
mode={mode}
|
||||
show={showAll}
|
||||
>
|
||||
{list[index] || ''}
|
||||
</OneSymbol>
|
||||
));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${style.show_symbol_wrapper}`}
|
||||
style={{
|
||||
paddingTop: mode === 'table-row' ? '8px' : 0,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
mode={mode}
|
||||
onClick={() => setShowAll(true)}
|
||||
>
|
||||
»
|
||||
</Button>
|
||||
{line}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShowSymbol;
|
91
src/ts/components/ShowSymbol/styles/index.module.scss
Normal file
|
@ -0,0 +1,91 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.show_symbol_wrapper {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.show_symbol {
|
||||
--temp-font: var(--font-s);
|
||||
--temp-width: 30px;
|
||||
--temp-height: 40px;
|
||||
user-select: none;
|
||||
|
||||
&_s {
|
||||
--temp-font: var(--font-xxs);
|
||||
--temp-width: 20px;
|
||||
--temp-height: 30px;
|
||||
}
|
||||
|
||||
font-size: var(--temp-font);
|
||||
position: relative;
|
||||
|
||||
display: inline-block;
|
||||
width: var(--temp-width);
|
||||
height: var(--temp-height);
|
||||
padding: 0;
|
||||
margin: 0 var(--space-xxs) 0 0;
|
||||
|
||||
vertical-align: top;
|
||||
text-transform: capitalize;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: var(--temp-height);
|
||||
transform: rotateY(180deg);
|
||||
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-black);
|
||||
background-color: white;
|
||||
|
||||
&_hide {
|
||||
animation-name: show_symbol;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
|
||||
&_bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
cursor: pointer;
|
||||
background-color: var(--color-black);
|
||||
|
||||
&_hide {
|
||||
// pointer-events: none;
|
||||
animation-name: show_symbol_bg;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.show_symbol_hide,
|
||||
.show_symbol_bg_hide {
|
||||
animation-iteration-count: 1;
|
||||
animation-direction: alternate;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@keyframes show_symbol {
|
||||
from {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
to {
|
||||
transform: rotateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show_symbol_bg {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
99% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useEffect } from 'react';
|
||||
|
||||
import Logo from 'ts/pages/PageWrapper/components/sidebar/Logo';
|
||||
import globalScroll from 'ts/helpers/globalScroll';
|
||||
|
||||
import style from './index.module.scss';
|
||||
import progress from './progress.module.scss';
|
||||
|
@ -8,11 +9,7 @@ import progress from './progress.module.scss';
|
|||
function SplashScreen(): React.ReactElement | null {
|
||||
|
||||
useEffect(() => {
|
||||
const overflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
setTimeout(() => {
|
||||
document.body.style.overflow = overflow;
|
||||
}, 5400);
|
||||
globalScroll.off(5400);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
||||
interface ITitleProps {
|
||||
title: string,
|
||||
}
|
||||
|
||||
function Title({ title }: ITitleProps): React.ReactElement | null {
|
||||
const [show, setShow] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<div className={`${style.tv100and1_cell_title}`}>
|
||||
{title}
|
||||
<button
|
||||
className={`${style.tv100and1_button} ${show ? style.animation : ''}`}
|
||||
onClick={() => {
|
||||
setShow(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Title;
|
|
@ -1,51 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import LineChart from 'ts/components/LineChart';
|
||||
import getOptions from 'ts/components/LineChart/helpers/getOptions';
|
||||
|
||||
import Title from './components/Title';
|
||||
import style from './styles/index.module.scss';
|
||||
|
||||
interface ITv100And1Props {
|
||||
rows: {
|
||||
title: string,
|
||||
value: number,
|
||||
}[];
|
||||
}
|
||||
|
||||
function Tv100And1({
|
||||
rows = [],
|
||||
}: ITv100And1Props): React.ReactElement | null {
|
||||
if (!rows || !rows.length) return null;
|
||||
|
||||
const chartOptions = getOptions({ max: rows[0].value, suffix: 'сиволов' });
|
||||
const formattedRows = rows.map((row: any) => (
|
||||
<div
|
||||
key={row.title}
|
||||
className={`${style.tv100and1_row}`}
|
||||
>
|
||||
<Title title={row.title} />
|
||||
<div className={`${style.tv100and1_cell_value}`}>
|
||||
{row.value}
|
||||
</div>
|
||||
<div className={`${style.tv100and1_cell_chart}`}>
|
||||
<LineChart
|
||||
options={chartOptions}
|
||||
value={row.value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={`${style.tv100and1}`}>
|
||||
{formattedRows}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Tv100And1.defaultProps = {
|
||||
rows: [],
|
||||
};
|
||||
|
||||
export default Tv100And1;
|
|
@ -1,90 +0,0 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.tv100and1 {
|
||||
&_row {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&_cell_title,
|
||||
&_cell_value,
|
||||
&_cell_chart {
|
||||
position: relative;
|
||||
font-size: var(--font-xs);
|
||||
|
||||
display: inline-block;
|
||||
padding: var(--space-m) 0;
|
||||
|
||||
line-height: var(--table-cell-height);
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&_cell_title {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
&_cell_value {
|
||||
width: 50px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&_cell_chart {
|
||||
width: calc(100% - 300px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&_button {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 2px;
|
||||
|
||||
display: block;
|
||||
height: calc(100% - 4px);
|
||||
|
||||
transform: rotate3d(1, 0, 0, 0);
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
background-color: var(--color-grey);
|
||||
background-image: url('../../../../assets/games/tv100and1.png');
|
||||
background-repeat: repeat-x;
|
||||
background-size: auto 100%;
|
||||
|
||||
&.animation {
|
||||
animation-name: tv_100_and_1;
|
||||
animation-iteration-count: 1;
|
||||
animation-duration: 1s;
|
||||
animation-direction: alternate;
|
||||
animation-timing-function: ease-in;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tv_100_and_1 {
|
||||
from {
|
||||
transform: rotate3d(1, 0, 0, 0);
|
||||
}
|
||||
10% {
|
||||
transform: rotate3d(1, 0, 0, 90deg);
|
||||
}
|
||||
25% {
|
||||
transform: rotate3d(1, 0, 0, 0);
|
||||
}
|
||||
55% {
|
||||
transform: rotate3d(1, 0, 0, 90deg);
|
||||
}
|
||||
80% {
|
||||
transform: rotate3d(1, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
transform: rotate3d(1, 0, 0, 90deg);
|
||||
}
|
||||
}
|
49
src/ts/helpers/FileGrip/components/author.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import IHashMap from 'ts/interfaces/HashMap';
|
||||
import { IDirtyFile } from 'ts/interfaces/FileInfo';
|
||||
|
||||
export default class FileGripByAuthor {
|
||||
addedFilesByAuthor: IHashMap<number> = {};
|
||||
|
||||
addedWithoutRemoveFilesByAuthor: IHashMap<number> = {};
|
||||
|
||||
removedFilesByAuthor: IHashMap<number> = {};
|
||||
|
||||
totalAddedFiles: number = 0;
|
||||
|
||||
clear() {
|
||||
this.addedFilesByAuthor = {};
|
||||
this.addedWithoutRemoveFilesByAuthor = {};
|
||||
this.removedFilesByAuthor = {};
|
||||
this.totalAddedFiles = 0;
|
||||
}
|
||||
|
||||
addFile(file: IDirtyFile) {
|
||||
const create = file?.firstCommit?.author || '';
|
||||
const remove = file?.lastCommit?.author || '';
|
||||
|
||||
if (!(create || remove) || file?.name?.[0] === '.') return;
|
||||
|
||||
this.#addNewAuthor(create);
|
||||
this.#addNewAuthor(remove);
|
||||
|
||||
this.addedWithoutRemoveFilesByAuthor[create] += 1;
|
||||
if (file.action !== 'D') {
|
||||
this.addedFilesByAuthor[create] += 1;
|
||||
} else {
|
||||
this.removedFilesByAuthor[remove] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#addNewAuthor(author: string) {
|
||||
const value = this.addedFilesByAuthor[author];
|
||||
if (value || value === 0) return;
|
||||
this.addedFilesByAuthor[author] = 0;
|
||||
this.addedWithoutRemoveFilesByAuthor[author] = 0;
|
||||
this.removedFilesByAuthor[author] = 0;
|
||||
}
|
||||
|
||||
updateTotalInfo() {
|
||||
this.totalAddedFiles = Object.values(this.addedFilesByAuthor)
|
||||
.reduce((sum: number, value: number) => sum + value, 0);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import FileBuilder from './components/FileBuilder';
|
|||
import FileGripByExtension from './components/extension';
|
||||
import FileGripByType from './components/type';
|
||||
import FileGripByFolder from './components/folder';
|
||||
import FileGripByAuthor from './components/author';
|
||||
|
||||
class FileGrip {
|
||||
files: any = new FileBuilder();
|
||||
|
@ -17,12 +18,15 @@ class FileGrip {
|
|||
|
||||
removedTree: any = new FileGripByFolder();
|
||||
|
||||
author: any = new FileGripByAuthor();
|
||||
|
||||
clear() {
|
||||
this.files.clear();
|
||||
this.extension.clear();
|
||||
this.type.clear();
|
||||
this.tree.clear();
|
||||
this.removedTree.clear();
|
||||
this.author.clear();
|
||||
}
|
||||
|
||||
addCommit(commit: ICommit | ISystemCommit) {
|
||||
|
@ -37,6 +41,7 @@ class FileGrip {
|
|||
this.files.updateTotalInfo((file: IDirtyFile) => {
|
||||
this.extension.addFile(file);
|
||||
this.type.addFile(file);
|
||||
this.author.addFile(file);
|
||||
if (file.action !== 'D') {
|
||||
this.tree.addFile(file);
|
||||
} else {
|
||||
|
@ -46,6 +51,7 @@ class FileGrip {
|
|||
|
||||
this.extension.updateTotalInfo();
|
||||
this.type.updateTotalInfo();
|
||||
this.author.updateTotalInfo();
|
||||
this.tree.updateTotalInfo();
|
||||
this.removedTree.updateTotalInfo();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,10 @@ export default {
|
|||
haveNotEmail: ACHIEVEMENT_TYPE.NORMAL, // Почтальон Печкин. Не заполнил поле e-mail
|
||||
hasCommitFrom0to7: ACHIEVEMENT_TYPE.BAD, // Ночной дозор
|
||||
longWaitPR: ACHIEVEMENT_TYPE.BAD, // Обещать не значит жениться, ожидание PR больше месяца
|
||||
lastCommit: ACHIEVEMENT_TYPE.NORMAL, // Я закончил. последний коммит на проекте
|
||||
longTask: ACHIEVEMENT_TYPE.BAD, // Вроде изян. работал над задачей больше трех месяцев
|
||||
noCommitOnDay: ACHIEVEMENT_TYPE.NORMAL, // Технический перерыв
|
||||
firstCommit: ACHIEVEMENT_TYPE.NORMAL, // Кто первый, того и тапки. первый коммит на проекте
|
||||
|
||||
// Типаж Козерога, по месяцу первого коммита
|
||||
horoscope1: ACHIEVEMENT_TYPE.NORMAL, // козерог
|
||||
|
@ -66,15 +70,11 @@ export default {
|
|||
|
||||
// нет картинки
|
||||
longestMessage: ACHIEVEMENT_TYPE.NORMAL, // А разговоров то было...
|
||||
noCommitOnDay: ACHIEVEMENT_TYPE.NORMAL, // Технический перерыв
|
||||
commitsAfter1800: ACHIEVEMENT_TYPE.GOOD, // Делу время
|
||||
more3YearsInProject: ACHIEVEMENT_TYPE.GOOD, // Старожил. больше 3х лет на проекте
|
||||
firstCommit: ACHIEVEMENT_TYPE.NORMAL, // Кто первый, того и тапки. первый коммит на проекте
|
||||
lastCommit: ACHIEVEMENT_TYPE.NORMAL, // Я закончил. последний коммит на проекте
|
||||
moreLintHint: ACHIEVEMENT_TYPE.GOOD, // Грамар-наци. Больше всех внес в .eslintrc .stylelintrc.json
|
||||
moreAddedFolders: ACHIEVEMENT_TYPE.NORMAL, // Директор, создал больше всех дирректорий
|
||||
workOnWeekends: ACHIEVEMENT_TYPE.BAD, // Работа не walk. хоть раз работал на выходных
|
||||
longTask: ACHIEVEMENT_TYPE.BAD, // Вроде изян. работал над задачей больше трех месяцев
|
||||
fileRush: ACHIEVEMENT_TYPE.NORMAL, // Зерг Раш. Создал больше всех файлов в проекте
|
||||
|
||||
// нет кода
|
||||
|
|
24
src/ts/helpers/globalScroll.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
let overflow = document.body.style.overflow;
|
||||
|
||||
function on() {
|
||||
document.body.style.overflow = overflow;
|
||||
}
|
||||
|
||||
function off(delay?: number) {
|
||||
overflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
if (delay) setTimeout(on, delay);
|
||||
}
|
||||
|
||||
function useOnOff() {
|
||||
off();
|
||||
return () => {
|
||||
on();
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
on,
|
||||
off,
|
||||
useOnOff,
|
||||
};
|
9
src/ts/helpers/random.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export function getRandom(max: number): number {
|
||||
return Math.floor(Math.random() * (max - 0 + 1)) + 0;
|
||||
}
|
||||
|
||||
export function shuffle(items: any[]): any[] {
|
||||
// @ts-ignore
|
||||
for (let j, x, i = items.length; i; j = parseInt(Math.random() * i), x = items[--i], items[i] = items[j], items[j] = x) {}
|
||||
return items;
|
||||
}
|
|
@ -47,7 +47,7 @@ export const TEAM = [
|
|||
id: 'day',
|
||||
link: '/team/day',
|
||||
title: 'sidebar.team.day',
|
||||
icon: './assets/menu/team_week.svg',
|
||||
icon: './assets/menu/team_day.svg',
|
||||
},
|
||||
{
|
||||
id: 'week',
|
||||
|
@ -59,13 +59,13 @@ export const TEAM = [
|
|||
id: 'month',
|
||||
link: '/team/month',
|
||||
title: 'sidebar.team.month',
|
||||
icon: './assets/menu/team_date_1.svg',
|
||||
icon: './assets/menu/team_month.svg',
|
||||
},
|
||||
{
|
||||
id: 'hours',
|
||||
link: '/team/hours',
|
||||
title: 'sidebar.team.hours',
|
||||
icon: './assets/menu/team_date_2.svg',
|
||||
icon: './assets/menu/team_hours.svg',
|
||||
},
|
||||
{},
|
||||
{
|
||||
|
@ -78,25 +78,25 @@ export const TEAM = [
|
|||
id: 'removedFiles',
|
||||
link: '/team/removedFiles',
|
||||
title: 'sidebar.team.removedFiles',
|
||||
icon: './assets/menu/team_files.svg',
|
||||
icon: './assets/menu/team_files_remove.svg',
|
||||
},
|
||||
{
|
||||
id: 'extension',
|
||||
link: '/team/extension',
|
||||
title: 'sidebar.team.extension',
|
||||
icon: './assets/menu/team_files.svg',
|
||||
icon: './assets/menu/team_files_ext.svg',
|
||||
},
|
||||
{
|
||||
id: 'tasks',
|
||||
link: '/team/tasks',
|
||||
title: 'sidebar.team.tasks',
|
||||
icon: './assets/menu/team_date_1.svg',
|
||||
icon: './assets/menu/team_tasks.svg',
|
||||
},
|
||||
{
|
||||
id: 'release',
|
||||
link: '/team/release',
|
||||
title: 'sidebar.team.release',
|
||||
icon: './assets/menu/team_date_1.svg',
|
||||
icon: './assets/menu/team_release.svg',
|
||||
},
|
||||
{},
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ export const PERSON = [
|
|||
id: 'day',
|
||||
link: '/person/day/',
|
||||
title: 'sidebar.person.day',
|
||||
icon: './assets/menu/team_week.svg',
|
||||
icon: './assets/menu/team_day.svg',
|
||||
},
|
||||
{
|
||||
id: 'week',
|
||||
|
@ -155,20 +155,20 @@ export const PERSON = [
|
|||
id: 'month',
|
||||
link: '/person/month/',
|
||||
title: 'sidebar.person.month',
|
||||
icon: './assets/menu/team_date_1.svg',
|
||||
icon: './assets/menu/team_month.svg',
|
||||
},
|
||||
{
|
||||
id: 'hours',
|
||||
link: '/person/hours/',
|
||||
title: 'sidebar.person.hours',
|
||||
icon: './assets/menu/team_date_2.svg',
|
||||
icon: './assets/menu/team_hours.svg',
|
||||
},
|
||||
{},
|
||||
{
|
||||
id: 'tasks',
|
||||
link: '/person/tasks/',
|
||||
title: 'sidebar.person.tasks',
|
||||
icon: './assets/menu/team_date_1.svg',
|
||||
icon: './assets/menu/team_tasks.svg',
|
||||
},
|
||||
{},
|
||||
{
|
||||
|
|
|
@ -3,20 +3,19 @@ import { observer } from 'mobx-react-lite';
|
|||
|
||||
import dataGripStore from 'ts/store/DataGrip';
|
||||
|
||||
import PageWrapper from 'ts/components/Page/wrapper';
|
||||
import Title from 'ts/components/Title';
|
||||
import Races from 'ts/components/Races';
|
||||
import CityBuilder from 'ts/components/CityBuilder';
|
||||
|
||||
import Tv100And1 from 'ts/components/Tv100And1';
|
||||
|
||||
import DataView from 'ts/components/DataView';
|
||||
import ShowSymbol from 'ts/components/ShowSymbol';
|
||||
import Column from 'ts/components/Table/components/Column';
|
||||
import LineChart from 'ts/components/LineChart';
|
||||
import getOptions from 'ts/components/LineChart/helpers/getOptions';
|
||||
import { ColumnTypesEnum } from 'ts/components/Table/interfaces/Column';
|
||||
|
||||
const Top = observer((): React.ReactElement => {
|
||||
const TeamBuilding = observer((): React.ReactElement => {
|
||||
const filesByAuthor = dataGripStore.fileGrip.author?.addedFilesByAuthor;
|
||||
|
||||
const tracksAuth = dataGripStore.dataGrip.author.statistic
|
||||
.filter((item: any) => !item.isStaff);
|
||||
|
@ -36,42 +35,77 @@ const Top = observer((): React.ReactElement => {
|
|||
<>
|
||||
<Title title="Скорость закрытия задач"/>
|
||||
<Races tracks={tracks} />
|
||||
<Title title="Объем созданных файлов"/>
|
||||
<CityBuilder />
|
||||
{'Небоскребы вверх ввиде графика'}
|
||||
|
||||
<Title title="Максимальная длинна подписи коммита"/>
|
||||
<Tv100And1 rows={maxMessageLength} />
|
||||
<DataView rows={maxMessageLength}>
|
||||
<Column
|
||||
isFixed
|
||||
title="Сотрудник"
|
||||
properties="title"
|
||||
template={(text: string) => (
|
||||
<ShowSymbol
|
||||
text={text}
|
||||
length={14}
|
||||
mode="table-row"
|
||||
/>
|
||||
)}
|
||||
width={360}
|
||||
/>
|
||||
<Column
|
||||
template={ColumnTypesEnum.SHORT_NUMBER}
|
||||
properties="value"
|
||||
width={50}
|
||||
/>
|
||||
<Column
|
||||
title="Количество символов"
|
||||
properties="value"
|
||||
template={(messageLength: number) => (
|
||||
<LineChart
|
||||
options={chartMessageLength}
|
||||
value={messageLength}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</DataView>
|
||||
|
||||
<PageWrapper template="table">
|
||||
<DataView rows={maxMessageLength}>
|
||||
<Column
|
||||
isFixed
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Сотрудник"
|
||||
properties="title"
|
||||
width={260}
|
||||
/>
|
||||
<Column
|
||||
template={ColumnTypesEnum.SHORT_NUMBER}
|
||||
properties="value"
|
||||
width={40}
|
||||
/>
|
||||
<Column
|
||||
title="Количество символов"
|
||||
properties="value"
|
||||
template={(messageLength: number) => (
|
||||
<LineChart
|
||||
options={chartMessageLength}
|
||||
value={messageLength}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</DataView>
|
||||
</PageWrapper>
|
||||
<Title title="Количество созданных файлов, если бы это был город"/>
|
||||
<CityBuilder valuesByTitle={filesByAuthor} />
|
||||
|
||||
<Title title="Количество созданных папок"/>
|
||||
<DataView rows={maxMessageLength}>
|
||||
<Column
|
||||
isFixed
|
||||
title="Сотрудник"
|
||||
properties="title"
|
||||
template={(text: string) => (
|
||||
<ShowSymbol
|
||||
text={text}
|
||||
length={14}
|
||||
mode="table-row"
|
||||
/>
|
||||
)}
|
||||
width={360}
|
||||
/>
|
||||
<Column
|
||||
template={ColumnTypesEnum.SHORT_NUMBER}
|
||||
properties="value"
|
||||
width={50}
|
||||
/>
|
||||
<Column
|
||||
title="Количество символов"
|
||||
properties="value"
|
||||
template={(messageLength: number) => (
|
||||
<LineChart
|
||||
options={chartMessageLength}
|
||||
value={messageLength}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</DataView>
|
||||
|
||||
{'Небоскребы вверх ввиде графика'}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default Top;
|
||||
export default TeamBuilding;
|
||||
|
|
|
@ -18,7 +18,7 @@ import Type from './components/Type';
|
|||
import Week from './components/Week';
|
||||
import Month from './components/Month';
|
||||
import Tasks from './components/Tasks';
|
||||
import Top from './components/Top';
|
||||
import TeamBuilding from './components/Top';
|
||||
import Pr from './components/PR';
|
||||
import Print from './components/Print';
|
||||
import Release from './components/Release';
|
||||
|
@ -41,7 +41,7 @@ function getViewById(page?: string) {
|
|||
if (page === 'commits') return <Commits/>;
|
||||
if (page === 'changes') return <Changes/>;
|
||||
if (page === 'words') return <PopularWords mode={mode}/>;
|
||||
if (page === 'top') return <Top/>;
|
||||
if (page === 'building') return <TeamBuilding/>;
|
||||
if (page === 'print') return <Print/>;
|
||||
if (page === 'tasks') return <Tasks/>;
|
||||
return <Total/>;
|
||||
|
|
|
@ -27,7 +27,7 @@ export default `
|
|||
§ sidebar.team.commits: All commits
|
||||
§ sidebar.team.changes: Alle Änderungen
|
||||
§ sidebar.team.words: Beliebte Wörter
|
||||
§ sidebar.team.top: Quiz
|
||||
§ sidebar.team.building: Quiz
|
||||
§ sidebar.team.settings: Die Einstellungen
|
||||
§ sidebar.person.total: Allgemeine Informationen
|
||||
§ sidebar.person.money: Arbeitskosten
|
||||
|
|
|
@ -27,7 +27,7 @@ export default `
|
|||
§ sidebar.team.commits: All commits
|
||||
§ sidebar.team.changes: All changes
|
||||
§ sidebar.team.words: Popular words
|
||||
§ sidebar.team.top: Quiz
|
||||
§ sidebar.team.building: Quiz
|
||||
§ sidebar.team.settings: Settings
|
||||
§ sidebar.person.total: Common info
|
||||
§ sidebar.person.money: Work cost
|
||||
|
|