Projects STRLCPY gradejs Commits dc99bd39
🤬
  • feat: rebase new icons, update storybook webpack config for svg-sprite, a bunch of simplicity, styling, consistency and decomposition fixes due to code review

  • Loading...
  • Dmitry Shakun committed 2 years ago
    dc99bd39
    1 parent bfa132b5
  • ■ ■ ■ ■ ■
    packages/web/.storybook/main.js
    1 1  const path = require('path');
     2 +const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
    2 3   
    3 4  module.exports = {
    4 5   stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
    skipped 11 lines
    16 17   {
    17 18   loader: 'css-loader',
    18 19   options: {
    19  - modules: {
    20  - exportLocalsConvention: 'camelCase',
    21  - },
     20 + modules: true,
    22 21   sourceMap: true,
    23 22   },
    24 23   },
    skipped 26 lines
    51 50   },
    52 51   ],
    53 52   });
     53 + 
     54 + config.module.rules = config.module.rules.map((rule) => {
     55 + if (rule.test && rule.test.toString().includes('svg')) {
     56 + const test = rule.test.toString().replace('svg|', '').replace(/\//g, '');
     57 + return { ...rule, test: new RegExp(test) };
     58 + } else {
     59 + return rule;
     60 + }
     61 + });
     62 + 
     63 + config.module.rules.push({
     64 + test: /\.svg$/,
     65 + include: path.resolve(__dirname, '../src/assets/icons/sprite'),
     66 + use: [
     67 + {
     68 + loader: 'svg-sprite-loader',
     69 + options: {
     70 + extract: true,
     71 + spriteFilename: 'sprite.svg',
     72 + },
     73 + },
     74 + ],
     75 + });
     76 + 
     77 + config.plugins.push(new SpriteLoaderPlugin());
    54 78   
    55 79   return config;
    56 80   },
    skipped 2 lines
  • packages/web/src/assets/icons/sprite/arrow.svg
  • packages/web/src/assets/icons/sprite/bug.svg
  • packages/web/src/assets/icons/sprite/logo.svg
  • packages/web/src/assets/icons/webpack.svg
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/icons/Arrow.tsx
    1  -import React from 'react';
    2  -import { IconProps } from './types';
    3  - 
    4  -export default function Arrow({
    5  - width = '24',
    6  - height = '24',
    7  - color = '#8E8AA0',
    8  - className,
    9  -}: IconProps) {
    10  - return (
    11  - <svg
    12  - width={width}
    13  - height={height}
    14  - className={className}
    15  - viewBox='0 0 10 18'
    16  - fill='none'
    17  - xmlns='http://www.w3.org/2000/svg'
    18  - >
    19  - <path
    20  - d='M1 1.67139L9 9.17139L1 16.6714'
    21  - stroke={color}
    22  - strokeWidth='2'
    23  - strokeLinecap='round'
    24  - strokeLinejoin='round'
    25  - />
    26  - </svg>
    27  - );
    28  -}
    29  - 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/icons/Bug.tsx
    1  -import React from 'react';
    2  -import { IconProps } from './types';
    3  - 
    4  -export default function Bug({
    5  - width = '24',
    6  - height = '24',
    7  - color = '#F3512E',
    8  - className,
    9  -}: IconProps) {
    10  - return (
    11  - <svg
    12  - width={width}
    13  - height={height}
    14  - className={className}
    15  - viewBox='0 0 24 23'
    16  - fill='none'
    17  - xmlns='http://www.w3.org/2000/svg'
    18  - >
    19  - <g opacity='0.5'>
    20  - <path
    21  - d='M19.1126 11.9117C19.1126 12.5345 19.0636 13.1427 18.9703 13.7303C18.7474 15.1342 18.2715 16.4206 17.6061 17.5085C16.3042 19.6367 14.277 21.0048 11.9998 21.0048C9.7226 21.0048 7.69536 19.6367 6.3935 17.5085C5.72808 16.4206 5.25217 15.1342 5.02925 13.7303C4.93595 13.1427 4.88697 12.5345 4.88697 11.9117C4.88697 10.8579 5.0272 9.84592 5.2851 8.90466C5.51141 8.07871 5.82833 7.3072 6.22062 6.60961C6.9705 5.27616 7.99577 4.21282 9.19 3.55564C10.0519 3.08134 11.0019 2.81862 11.9998 2.81862C12.9977 2.81862 13.9476 3.08134 14.8096 3.55564C16.0038 4.21282 17.0291 5.27616 17.7789 6.60961C18.1712 7.3072 18.4882 8.07871 18.7145 8.90466C18.9724 9.84592 19.1126 10.8579 19.1126 11.9117Z'
    22  - fill={color}
    23  - />
    24  - <path
    25  - d='M11.9998 21.0048V8.27447M11.9998 21.0048C14.277 21.0048 16.3042 19.6367 17.6061 17.5085M11.9998 21.0048C9.7226 21.0048 7.69536 19.6367 6.3935 17.5085M11.9998 8.27447C11.1107 8.27447 8.35447 8.18751 6.22062 6.60961M11.9998 8.27447C12.8889 8.27447 15.6451 8.18354 17.7789 6.60961M6.22062 6.60961C5.82833 7.3072 5.51141 8.07871 5.2851 8.90466M6.22062 6.60961C6.9705 5.27616 7.99577 4.21282 9.19 3.55564M17.7789 6.60961C18.1712 7.3072 18.4882 8.07871 18.7145 8.90466M17.7789 6.60961C17.0291 5.27616 16.0038 4.21282 14.8096 3.55564M17.6061 17.5085L20.8908 20.0955M17.6061 17.5085C18.2715 16.4206 18.7474 15.1342 18.9703 13.7303M18.9703 13.7303C19.0636 13.1427 19.1126 12.5345 19.1126 11.9117C19.1126 10.8579 18.9724 9.84592 18.7145 8.90466M18.9703 13.7303H22.669M18.7145 8.90466L21.7799 7.36516M5.2851 8.90466C5.0272 9.84592 4.88697 10.8579 4.88697 11.9117C4.88697 12.5345 4.93595 13.1427 5.02925 13.7303M5.2851 8.90466L2.21967 7.36516M6.66517 1L9.19 3.55564M9.19 3.55564C10.0519 3.08134 11.0019 2.81862 11.9998 2.81862C12.9977 2.81862 13.9476 3.08134 14.8096 3.55564M17.3344 1L14.8096 3.55564M1.33057 13.7303C2.56346 13.7303 5.02925 13.7303 5.02925 13.7303M5.02925 13.7303C5.25217 15.1342 5.72808 16.4206 6.3935 17.5085M3.10877 20.0955L6.3935 17.5085'
    26  - stroke={color}
    27  - strokeWidth='2'
    28  - strokeLinecap='round'
    29  - />
    30  - </g>
    31  - <path
    32  - d='M6.22119 6.60961C8.35503 8.18751 11.1112 8.27447 12.0004 8.27447C12.8895 8.27447 15.6457 8.18354 17.7795 6.60961C17.0296 5.27616 16.0044 4.21282 14.8101 3.55564C13.9482 3.08134 12.9983 2.81862 12.0004 2.81862C11.0024 2.81862 10.0525 3.08134 9.19057 3.55564C7.99633 4.21282 6.97106 5.27616 6.22119 6.60961Z'
    33  - fill={color}
    34  - />
    35  - <path
    36  - d='M12.0004 21.0048V8.27447M12.0004 8.27447C11.1112 8.27447 8.35503 8.18751 6.22119 6.60961C6.97106 5.27616 7.99633 4.21282 9.19057 3.55564M12.0004 8.27447C12.8895 8.27447 15.6457 8.18354 17.7795 6.60961C17.0296 5.27616 16.0044 4.21282 14.8101 3.55564M6.66574 1L9.19057 3.55564M9.19057 3.55564C10.0525 3.08134 11.0024 2.81862 12.0004 2.81862C12.9983 2.81862 13.9482 3.08134 14.8101 3.55564M17.335 1L14.8101 3.55564'
    37  - stroke={color}
    38  - strokeWidth='2'
    39  - strokeLinecap='round'
    40  - />
    41  - </svg>
    42  - );
    43  -}
    44  - 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/icons/Logo.tsx
    1  -import React from 'react';
    2  -import { IconProps } from './types';
    3  - 
    4  -export default function Logo({
    5  - width = '129',
    6  - height = '25',
    7  - color = '#fff',
    8  - className,
    9  -}: IconProps) {
    10  - return (
    11  - <svg
    12  - width={width}
    13  - height={height}
    14  - className={className}
    15  - viewBox='0 0 129 25'
    16  - fill='none'
    17  - xmlns='http://www.w3.org/2000/svg'
    18  - >
    19  - <path
    20  - d='M11.6023 24.3182C9.42803 24.3182 7.51515 23.8371 5.86364 22.875C4.21212 21.9053 2.92424 20.5303 2 18.75C1.07576 16.9621 0.613636 14.8409 0.613636 12.3864C0.613636 10.5 0.893939 8.81818 1.45455 7.34091C2.01515 5.85606 2.79545 4.59848 3.79545 3.56818C4.80303 2.53788 5.97348 1.75379 7.30682 1.21591C8.64015 0.678029 10.072 0.40909 11.6023 0.40909C12.9205 0.40909 14.1515 0.602272 15.2955 0.988636C16.447 1.36742 17.4735 1.9053 18.375 2.60227C19.2765 3.29167 20.0114 4.11742 20.5795 5.07954C21.1553 6.03409 21.5227 7.09091 21.6818 8.25H16.7045C16.5455 7.69697 16.3144 7.20833 16.0114 6.78409C15.7159 6.35227 15.3485 5.98864 14.9091 5.69318C14.4773 5.39015 13.9886 5.15909 13.4432 5C12.9053 4.84091 12.3182 4.76136 11.6818 4.76136C10.5 4.76136 9.45076 5.05682 8.53409 5.64773C7.61742 6.23864 6.89773 7.09848 6.375 8.22727C5.85985 9.34848 5.60227 10.7197 5.60227 12.3409C5.60227 13.9621 5.84849 15.3409 6.34091 16.4773C6.84091 17.6136 7.54167 18.4811 8.44318 19.0795C9.3447 19.6705 10.4053 19.9659 11.625 19.9659C12.7614 19.9659 13.7311 19.7614 14.5341 19.3523C15.3371 18.9356 15.9508 18.3598 16.375 17.625C16.8068 16.8826 17.0227 16.0265 17.0227 15.0568L17.9545 15.25H11.9318V11.5455H21.875V24H18.5114L18.2273 21.3409H18.1023C17.322 22.2879 16.3977 23.0227 15.3295 23.5455C14.2689 24.0606 13.0265 24.3182 11.6023 24.3182ZM24.5031 24V6.54545H29.1963V9.59091H29.3781C29.6963 8.50758 30.2303 7.68939 30.9803 7.13636C31.7303 6.57576 32.594 6.29545 33.5713 6.29545C34.0409 6.29545 34.4766 6.35227 34.8781 6.46591C35.2796 6.57955 35.6394 6.73485 35.9576 6.93182L34.5031 10.9318C34.2758 10.8182 34.0258 10.7235 33.7531 10.6477C33.4879 10.5644 33.1887 10.5227 32.8553 10.5227C32.2038 10.5227 31.6129 10.678 31.0826 10.9886C30.5523 11.2917 30.1319 11.7121 29.8213 12.25C29.5106 12.7879 29.3516 13.4129 29.344 14.125V24H24.5031ZM42.6624 24.2841C41.3366 24.2841 40.1359 23.9432 39.0601 23.2614C37.9919 22.572 37.1434 21.5606 36.5147 20.2273C35.8934 18.8864 35.5828 17.2424 35.5828 15.2955C35.5828 13.2955 35.9048 11.6326 36.5488 10.3068C37.1927 8.97348 38.0488 7.97727 39.1169 7.31818C40.1927 6.65152 41.3707 6.31818 42.651 6.31818C43.6283 6.31818 44.4427 6.48485 45.0942 6.81818C45.7533 7.14394 46.2836 7.55303 46.6851 8.04545C47.0942 8.5303 47.4048 9.00758 47.6169 9.47727H47.7647V6.54545H52.5942V24H47.8215V21.2045H47.6169C47.3897 21.6894 47.0677 22.1705 46.651 22.6477C46.2419 23.1174 45.7078 23.5076 45.0488 23.8182C44.3972 24.1288 43.6018 24.2841 42.6624 24.2841ZM44.1965 20.4318C44.9768 20.4318 45.6359 20.2197 46.1738 19.7955C46.7192 19.3636 47.1359 18.7614 47.4238 17.9886C47.7192 17.2159 47.8669 16.3106 47.8669 15.2727C47.8669 14.2348 47.723 13.3333 47.4351 12.5682C47.1472 11.803 46.7306 11.2121 46.1851 10.7955C45.6397 10.3788 44.9768 10.1705 44.1965 10.1705C43.401 10.1705 42.7306 10.3864 42.1851 10.8182C41.6397 11.25 41.2268 11.8485 40.9465 12.6136C40.6662 13.3788 40.526 14.2652 40.526 15.2727C40.526 16.2879 40.6662 17.1856 40.9465 17.9659C41.2344 18.7386 41.6472 19.3447 42.1851 19.7841C42.7306 20.2159 43.401 20.4318 44.1965 20.4318ZM62.0461 24.2841C60.7204 24.2841 59.5196 23.9432 58.4439 23.2614C57.3757 22.572 56.5272 21.5606 55.8984 20.2273C55.2772 18.8864 54.9666 17.2424 54.9666 15.2955C54.9666 13.2955 55.2886 11.6326 55.9325 10.3068C56.5764 8.97348 57.4325 7.97727 58.5007 7.31818C59.5764 6.65152 60.7545 6.31818 62.0348 6.31818C63.012 6.31818 63.8264 6.48485 64.478 6.81818C65.137 7.14394 65.6673 7.55303 66.0689 8.04545C66.478 8.5303 66.7886 9.00758 67.0007 9.47727H67.1484V0.727272H71.978V24H67.2052V21.2045H67.0007C66.7734 21.6894 66.4514 22.1705 66.0348 22.6477C65.6257 23.1174 65.0916 23.5076 64.4325 23.8182C63.781 24.1288 62.9855 24.2841 62.0461 24.2841ZM63.5802 20.4318C64.3605 20.4318 65.0196 20.2197 65.5575 19.7955C66.103 19.3636 66.5196 18.7614 66.8075 17.9886C67.103 17.2159 67.2507 16.3106 67.2507 15.2727C67.2507 14.2348 67.1067 13.3333 66.8189 12.5682C66.531 11.803 66.1143 11.2121 65.5689 10.7955C65.0234 10.3788 64.3605 10.1705 63.5802 10.1705C62.7848 10.1705 62.1143 10.3864 61.5689 10.8182C61.0234 11.25 60.6105 11.8485 60.3302 12.6136C60.0499 13.3788 59.9098 14.2652 59.9098 15.2727C59.9098 16.2879 60.0499 17.1856 60.3302 17.9659C60.6181 18.7386 61.031 19.3447 61.5689 19.7841C62.1143 20.2159 62.7848 20.4318 63.5802 20.4318ZM82.9526 24.3409C81.1572 24.3409 79.6117 23.9773 78.3163 23.25C77.0284 22.5152 76.036 21.4773 75.339 20.1364C74.642 18.7879 74.2935 17.1932 74.2935 15.3523C74.2935 13.5568 74.642 11.9811 75.339 10.625C76.036 9.26894 77.017 8.21212 78.2822 7.45454C79.5549 6.69697 81.0473 6.31818 82.7594 6.31818C83.911 6.31818 84.9829 6.50379 85.9753 6.875C86.9753 7.23864 87.8466 7.78788 88.589 8.52273C89.339 9.25758 89.9223 10.1818 90.339 11.2955C90.7556 12.4015 90.964 13.697 90.964 15.1818V16.5114H76.2253V13.5114H86.4072C86.4072 12.8144 86.2556 12.197 85.9526 11.6591C85.6496 11.1212 85.2291 10.7008 84.6913 10.3977C84.161 10.0871 83.5435 9.93182 82.839 9.93182C82.1041 9.93182 81.4526 10.1023 80.8844 10.4432C80.3238 10.7765 79.8844 11.2273 79.5663 11.7955C79.2481 12.3561 79.0852 12.9811 79.0776 13.6705V16.5227C79.0776 17.3864 79.2367 18.1326 79.5549 18.7614C79.8806 19.3902 80.339 19.875 80.9299 20.2159C81.5208 20.5568 82.2216 20.7273 83.0322 20.7273C83.57 20.7273 84.0625 20.6515 84.5094 20.5C84.9564 20.3485 85.339 20.1212 85.6572 19.8182C85.9753 19.5152 86.2178 19.1439 86.3844 18.7045L90.8617 19C90.6344 20.0758 90.1685 21.0152 89.464 21.8182C88.767 22.6136 87.8655 23.2348 86.7594 23.6818C85.661 24.1212 84.392 24.3409 82.9526 24.3409ZM102.572 0.727272H107.436V16.9545C107.436 18.4545 107.099 19.7576 106.424 20.8636C105.758 21.9697 104.83 22.822 103.64 23.4205C102.451 24.0189 101.068 24.3182 99.4926 24.3182C98.0911 24.3182 96.8184 24.072 95.6744 23.5795C94.5381 23.0795 93.6366 22.322 92.9699 21.3068C92.3032 20.2841 91.9737 19 91.9812 17.4545H96.879C96.8941 18.0682 97.0191 18.5947 97.254 19.0341C97.4964 19.4659 97.8259 19.7992 98.2426 20.0341C98.6669 20.2614 99.1669 20.375 99.7426 20.375C100.349 20.375 100.86 20.2462 101.277 19.9886C101.701 19.7235 102.023 19.3371 102.243 18.8295C102.462 18.322 102.572 17.697 102.572 16.9545V0.727272ZM123.169 7.42045C123.078 6.50379 122.688 5.79167 121.999 5.28409C121.309 4.77651 120.374 4.52273 119.192 4.52273C118.389 4.52273 117.711 4.63636 117.158 4.86364C116.605 5.08333 116.18 5.39015 115.885 5.78409C115.597 6.17803 115.453 6.625 115.453 7.125C115.438 7.54167 115.525 7.9053 115.714 8.21591C115.911 8.52652 116.18 8.79545 116.521 9.02273C116.862 9.24242 117.256 9.43561 117.703 9.60227C118.15 9.76136 118.627 9.89773 119.135 10.0114L121.226 10.5114C122.241 10.7386 123.173 11.0417 124.021 11.4205C124.87 11.7992 125.605 12.2652 126.226 12.8182C126.847 13.3712 127.328 14.0227 127.669 14.7727C128.017 15.5227 128.195 16.3826 128.203 17.3523C128.195 18.7765 127.832 20.0114 127.112 21.0568C126.4 22.0947 125.37 22.9015 124.021 23.4773C122.68 24.0455 121.063 24.3295 119.169 24.3295C117.29 24.3295 115.654 24.0417 114.26 23.4659C112.874 22.8902 111.79 22.0379 111.01 20.9091C110.237 19.7727 109.832 18.3674 109.794 16.6932H114.555C114.608 17.4735 114.832 18.125 115.226 18.6477C115.627 19.1629 116.161 19.553 116.828 19.8182C117.502 20.0758 118.264 20.2045 119.112 20.2045C119.945 20.2045 120.669 20.0833 121.283 19.8409C121.904 19.5985 122.385 19.2614 122.726 18.8295C123.067 18.3977 123.237 17.9015 123.237 17.3409C123.237 16.8182 123.082 16.3788 122.771 16.0227C122.468 15.6667 122.021 15.3636 121.43 15.1136C120.847 14.8636 120.131 14.6364 119.283 14.4318L116.749 13.7955C114.786 13.3182 113.237 12.572 112.101 11.5568C110.964 10.5417 110.4 9.17424 110.408 7.45454C110.4 6.04545 110.775 4.81439 111.533 3.76136C112.298 2.70833 113.347 1.88636 114.68 1.29545C116.014 0.704545 117.529 0.40909 119.226 0.40909C120.953 0.40909 122.461 0.704545 123.749 1.29545C125.044 1.88636 126.052 2.70833 126.771 3.76136C127.491 4.81439 127.862 6.03409 127.885 7.42045H123.169Z'
    21  - fill={color}
    22  - />
    23  - </svg>
    24  - );
    25  -}
    26  - 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/icons/Spinner.tsx
    1  -import React from 'react';
    2  -import { IconProps } from './types';
    3  - 
    4  -type SpinnerProps = IconProps & {
    5  - fromColor?: string;
    6  -};
    7  - 
    8  -export default function Spinner({
    9  - width = '32',
    10  - height = '32',
    11  - color = '#fff',
    12  - fromColor = '#009933',
    13  - className,
    14  -}: SpinnerProps) {
    15  - return (
    16  - <svg
    17  - width={width}
    18  - height={height}
    19  - className={className}
    20  - xmlns='http://www.w3.org/2000/svg'
    21  - fill='none'
    22  - viewBox='0 0 32 32'
    23  - >
    24  - <path
    25  - stroke='url(#spinner)'
    26  - strokeLinecap='round'
    27  - strokeLinejoin='round'
    28  - strokeWidth='4'
    29  - d='M16 30c7.732 0 14-6.268 14-14 0-7.73199-6.268-14-14-14C8.26801 2 2 8.26801 2 16c0 7.732 6.26801 14 14 14Z'
    30  - />
    31  - <defs>
    32  - <radialGradient
    33  - id='spinner'
    34  - cx='0'
    35  - cy='0'
    36  - r='1'
    37  - gradientTransform='matrix(0 -14 14 0 16 16)'
    38  - gradientUnits='userSpaceOnUse'
    39  - >
    40  - <stop stopColor={color} />
    41  - <stop offset='.0001' stopColor={fromColor} stopOpacity='0' />
    42  - <stop offset='.140625' stopColor={color} stopOpacity='0' />
    43  - </radialGradient>
    44  - </defs>
    45  - </svg>
    46  - );
    47  -}
    48  - 
  • ■ ■ ■ ■
    packages/web/src/components/layouts/Home/Home.tsx
    skipped 74 lines
    75 75   <a
    76 76   href='https://github.com/gradejs/gradejs/discussions/6'
    77 77   target='_blank'
    78  - rel='norefferer noreferrer'
     78 + rel='noreferrer'
    79 79   className={clsx(styles.learnMore)}
    80 80   >
    81 81   Learn more
    skipped 9 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/layouts/HomeNew/HomeNew.tsx
    1 1  import React from 'react';
     2 +import { CardProps } from '../../ui/Card/Card';
    2 3  import Hero from '../../ui/Hero/Hero';
    3 4  import Container from 'components/ui/Container/Container';
    4 5  import CardList from '../../ui/CardList/CardList';
    skipped 1 lines
    6 7  import Footer from '../../ui/Footer/Footer';
    7 8  import CardGroup from '../../ui/CardGroup/CardGroup';
    8 9   
    9  -export type HomeNewProps = {
     10 +type Props = {
    10 11   suggestions: string[];
    11 12  };
    12 13   
    13  -export default function HomeNew({ suggestions }: HomeNewProps) {
    14  - const popularCards = [
     14 +export default function HomeNew({ suggestions }: Props) {
     15 + const popularCards: CardProps[] = [
    15 16   {
     17 + id: 'uExBVGuF',
    16 18   title: 'github.com',
    17 19   icon: 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
    18 20   packageTags: {
    skipped 2 lines
    21 23   },
    22 24   },
    23 25   {
     26 + id: '1EkL1u5g',
    24 27   title: 'fingerprint.com',
    25 28   icon: 'https://avatars.githubusercontent.com/u/67208791?s=200&v=4',
    26 29   packageTags: {
    skipped 2 lines
    29 32   },
    30 33   },
    31 34   {
     35 + id: 'mhwO2bPM',
    32 36   title: 'facebook.com',
    33 37   icon: 'https://avatars.githubusercontent.com/u/69631?s=200&v=4',
    34 38   packageTags: {
    skipped 3 lines
    38 42   },
    39 43   ];
    40 44   
    41  - const popularPackages = [
     45 + const popularPackages: CardProps[] = [
    42 46   {
     47 + id: 'FPsBcl8R',
    43 48   title: '@team-griffin/react-heading-section',
    44 49   description: "This package's job is to automatically determine...",
    45 50   featuredSites: {
    skipped 6 lines
    52 57   },
    53 58   },
    54 59   {
     60 + id: 'emtYcsUh',
    55 61   title: 'unist-util-generated',
    56 62   description: 'unist utility to check if a node is generated',
    57 63   featuredSites: {
    skipped 6 lines
    64 70   },
    65 71   },
    66 72   {
     73 + id: 'TYIwvAfy',
    67 74   title: 'react-smooth',
    68 75   description: 'is a animation library work on React',
    69 76   featuredSites: {
    skipped 6 lines
    76 83   },
    77 84   },
    78 85   {
     86 + id: 'Lq1pEEX7',
    79 87   title: 'unist-util-position',
    80 88   description: 'unist utility to get the positional info of nodes',
    81 89   featuredSites: {
    skipped 6 lines
    88 96   },
    89 97   },
    90 98   {
     99 + id: 'cWOgIbmp',
    91 100   title: 'vfile-message',
    92 101   description: 'Create vfile messages',
    93 102   featuredSites: {
    skipped 6 lines
    100 109   },
    101 110   },
    102 111   {
     112 + id: 'UT97Vpoi',
    103 113   title: 'Go to all Popular packages',
    104 114   variant: 'toAll',
    105 115   },
    106 116   ];
    107 117   
    108  - const vulnerablePackages = [
     118 + const vulnerablePackages: CardProps[] = [
    109 119   {
     120 + id: 'LnO9Xynn',
    110 121   title: 'disneyland.omsk.ru/signup',
    111 122   vulnerablePackage: {
    112 123   name: 'mdast-util-from-markdown',
    skipped 1 lines
    114 125   variant: 'vulnerable',
    115 126   },
    116 127   {
     128 + id: '-A74UAy8',
    117 129   title: 'disneyland.omsk.ru/signup',
    118 130   vulnerablePackage: {
    119 131   name: 'mdast-util-from-markdown',
    skipped 2 lines
    122 134   variant: 'vulnerable',
    123 135   },
    124 136   {
     137 + id: 'DPa05I2W',
    125 138   title: 'disneyland.omsk.ru/signup',
    126 139   vulnerablePackage: {
    127 140   name: 'mdast-util-from-markdown',
    skipped 34 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/layouts/Website/Website.tsx
    skipped 93 lines
    94 94   <span className={styles.packagesTotal}>({packages.length})</span>
    95 95   <Filters onSubmit={onFiltersApply} />
    96 96   <Icon
    97  - kind={'lines'}
     97 + kind='lines'
    98 98   className={styles.viewSelect}
    99 99   color={view === 'lines' ? '#0F0F0F' : '#E6E6E6'}
    100 100   onClick={() => {
    skipped 2 lines
    103 103   }}
    104 104   />
    105 105   <Icon
    106  - kind={'grid'}
     106 + kind='grid'
    107 107   className={styles.viewSelect}
    108 108   color={view === 'grid' ? '#0F0F0F' : '#E6E6E6'}
    109 109   onClick={() => {
    skipped 38 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/AvatarGroup/AvatarGroup.module.scss
     1 +@import '~styles/_vars.scss';
     2 +@import '~styles/responsive.scss';
     3 + 
     4 +.avatarsWrapper {
     5 + flex: 1;
     6 + display: flex;
     7 + flex-direction: column;
     8 + justify-content: flex-end;
     9 +}
     10 + 
     11 +.avatars {
     12 + display: flex;
     13 + align-items: center;
     14 +}
     15 + 
     16 +.avatarGroup {
     17 + padding-left: 0;
     18 + margin-top: 0;
     19 + margin-bottom: 0;
     20 + list-style: none;
     21 + flex-shrink: 0;
     22 + display: flex;
     23 + align-items: center;
     24 + flex-direction: row-reverse;
     25 +}
     26 + 
     27 +.avatarItem {
     28 + width: 40px;
     29 + height: 40px;
     30 + border: 2px solid $white;
     31 + border-radius: 50%;
     32 + overflow: hidden;
     33 + flex-shrink: 0;
     34 + display: flex;
     35 + align-items: center;
     36 + justify-content: center;
     37 + user-select: none;
     38 + margin-left: -7px;
     39 + 
     40 + &:not(:first-child) {
     41 + margin-left: -7px;
     42 + }
     43 + 
     44 + &:last-child {
     45 + margin-left: 0;
     46 + }
     47 + 
     48 + @include mobile-and-tablet {
     49 + width: 36px;
     50 + height: 36px;
     51 + }
     52 +}
     53 + 
     54 +.avatarImage {
     55 + width: 100%;
     56 + height: 100%;
     57 + object-fit: cover;
     58 +}
     59 + 
     60 +.counter {
     61 + white-space: nowrap;
     62 + font-size: 19px;
     63 + line-height: 30px;
     64 + margin-left: 16px;
     65 + 
     66 + @include mobile-and-tablet {
     67 + font-size: 16px;
     68 + line-height: 1.62;
     69 + }
     70 +}
     71 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/AvatarGroup/AvatarGroup.stories.tsx
     1 +import React from 'react';
     2 +import { ComponentStory, ComponentMeta } from '@storybook/react';
     3 +import AvatarGroup from './AvatarGroup';
     4 + 
     5 +export default {
     6 + title: 'Interface / AvatarGroup',
     7 + component: AvatarGroup,
     8 + parameters: {
     9 + layout: 'centered',
     10 + },
     11 +} as ComponentMeta<typeof AvatarGroup>;
     12 + 
     13 +const Template: ComponentStory<typeof AvatarGroup> = (args) => <AvatarGroup {...args} />;
     14 + 
     15 +export const Default = Template.bind({});
     16 +Default.args = {
     17 + avatarGroup: [
     18 + 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
     19 + 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
     20 + 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
     21 + ],
     22 + counter: 5265,
     23 +};
     24 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/AvatarGroup/AvatarGroup.tsx
     1 +import React from 'react';
     2 +import styles from './AvatarGroup.module.scss';
     3 +import { formatNumber } from '../../../utils/helpers';
     4 + 
     5 +type Props = {
     6 + avatarGroup: string[];
     7 + counter: number;
     8 +};
     9 + 
     10 +export default function AvatarGroup({ avatarGroup, counter }: Props) {
     11 + return (
     12 + <div className={styles.avatarsWrapper}>
     13 + <div className={styles.avatars}>
     14 + <div className={styles.avatarGroup}>
     15 + {avatarGroup.map((avatar) => (
     16 + <div key={avatar} className={styles.avatarItem}>
     17 + <img src={avatar} className={styles.avatarImage} alt='' />
     18 + </div>
     19 + ))}
     20 + </div>
     21 + 
     22 + <div className={styles.counter}>+ {formatNumber(counter)} sites use</div>
     23 + </div>
     24 + </div>
     25 + );
     26 +}
     27 + 
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Card/Card.module.scss
    skipped 1 lines
    2 2  @import '~styles/responsive.scss';
    3 3   
    4 4  .card {
     5 + flex-shrink: 0;
    5 6   position: relative;
    6 7   background: #ffffff;
    7 8   border-radius: 24px;
    skipped 10 lines
    18 19   }
    19 20   
    20 21   @include mobile-and-tablet {
     22 + scroll-snap-align: start;
     23 + max-width: 314px;
    21 24   min-height: 204px;
    22 25   box-shadow: $shadow-small;
    23 26   }
    skipped 4 lines
    28 31   align-items: center;
    29 32  }
    30 33   
    31  -.icon {
     34 +.iconWrapper {
    32 35   flex-shrink: 0;
    33 36   margin-right: 16px;
    34 37   display: inline-flex;
     38 +}
    35 39   
    36  - img {
    37  - width: 100%;
    38  - max-width: 52px;
    39  - object-fit: cover;
    40  - }
     40 +.icon {
     41 + width: 100%;
     42 + max-width: 52px;
     43 + object-fit: cover;
    41 44  }
    42 45   
    43 46  .title {
    skipped 17 lines
    61 64   
    62 65  .tagsWrapper {
    63 66   margin-top: 28px;
    64  - flex: 1;
    65  - display: flex;
    66  - flex-direction: column;
    67 67   
    68 68   @include mobile-and-tablet {
    69 69   margin-top: 20px;
    70 70   }
    71 71  }
    72 72   
    73  -.tags {
    74  - display: flex;
    75  - flex-wrap: wrap;
    76  - align-items: center;
    77  - justify-content: flex-start;
    78  - 
    79  - & > * {
    80  - margin-bottom: 0.5rem;
    81  - }
    82  - 
    83  - & > *:not(:last-child) {
    84  - margin-right: 0.75rem;
    85  - }
    86  -}
    87  - 
    88  -.sitesWrapper {
    89  - flex: 1;
    90  - display: flex;
    91  - flex-direction: column;
    92  - justify-content: flex-end;
    93  -}
    94  - 
    95  -.sites {
    96  - display: flex;
    97  - align-items: center;
    98  -}
    99  - 
    100  -.sites-list {
    101  - padding-left: 0;
    102  - margin-top: 0;
    103  - margin-bottom: 0;
    104  - list-style: none;
    105  - flex-shrink: 0;
    106  - display: flex;
    107  - align-items: center;
    108  - flex-direction: row-reverse;
    109  - 
    110  - & > * + * {
    111  - margin-left: -7px;
    112  - }
    113  -}
    114  - 
    115  -.sites-item {
    116  - width: 40px;
    117  - height: 40px;
    118  - border: 2px solid $white;
    119  - border-radius: 50%;
    120  - overflow: hidden;
    121  - flex-shrink: 0;
    122  - display: flex;
    123  - align-items: center;
    124  - justify-content: center;
    125  - user-select: none;
    126  - margin-left: -7px;
    127  - 
    128  - &:last-child {
    129  - margin-left: 0;
    130  - }
    131  - 
    132  - img {
    133  - width: 100%;
    134  - height: 100%;
    135  - object-fit: cover;
    136  - }
    137  - 
    138  - @include mobile-and-tablet {
    139  - width: 36px;
    140  - height: 36px;
    141  - }
    142  -}
    143  - 
    144  -.sites-count {
    145  - white-space: nowrap;
    146  - font-size: 19px;
    147  - line-height: 30px;
    148  - margin-left: 16px;
    149  - 
    150  - @include mobile-and-tablet {
    151  - font-size: 16px;
    152  - line-height: 1.62;
    153  - }
    154  -}
    155  - 
    156 73  .toAll {
    157 74   background-color: $gray-surface;
    158 75  }
    skipped 13 lines
    172 89   box-shadow: $shadow;
    173 90   border: none;
    174 91   appearance: none;
    175  - padding: 0;
     92 + padding: 0 0 0 2px;
    176 93  }
    177 94   
    178 95  .vulnerable {
    skipped 14 lines
    193 110   }
    194 111  }
    195 112   
    196  -.vulnerableWrapper {
    197  - display: flex;
    198  - align-items: center;
    199  - margin-top: 16px;
    200  - margin-right: -9px;
    201  -}
    202  - 
    203  -.vulnerablePackage {
    204  - position: relative;
    205  - display: flex;
    206  - align-items: center;
    207  - font-size: 18px;
    208  - line-height: 24px;
    209  - font-family: $font-monospace;
    210  - color: $red-accent;
    211  - 
    212  - @include mobile-and-tablet {
    213  - font-size: 14px;
    214  - line-height: 20px;
    215  - }
    216  -}
    217  - 
    218  -.vulnerableIcon {
    219  - display: flex;
    220  - margin-right: 12px;
    221  -}
    222  - 
    223  -.vulnerableMore {
    224  - margin-left: 12px;
    225  -}
    226  - 
    227  -.vulnerableMoreText {
    228  - @include mobile-and-tablet {
    229  - display: none;
    230  - }
    231  -}
    232  - 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/Card/Card.stories.tsx
    skipped 13 lines
    14 14   
    15 15  export const PopularSearchQueries = Template.bind({});
    16 16  PopularSearchQueries.args = {
     17 + id: 'uExBVGuF',
    17 18   title: 'github.com',
    18 19   icon: 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
    19 20   packageTags: {
    skipped 4 lines
    24 25   
    25 26  export const PopularPackages = Template.bind({});
    26 27  PopularPackages.args = {
     28 + id: '1EkL1u5g',
    27 29   title: '@team-griffin/react-heading-section',
    28 30   description:
    29 31   'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
    skipped 9 lines
    39 41   
    40 42  export const VulnerableSites = Template.bind({});
    41 43  VulnerableSites.args = {
     44 + id: 'mhwO2bPM',
    42 45   title: 'disneyland.omsk.ru/signup',
    43 46   vulnerablePackage: {
    44 47   name: 'mdast-util-from-markdown',
    skipped 5 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Card/Card.tsx
    1 1  import React from 'react';
    2 2  import styles from './Card.module.scss';
    3 3  import clsx from 'clsx';
    4  -import { numberWithSpaces } from '../../../utils/helpers';
    5  -import { Bug } from 'components/icons';
    6 4  import Chip from '../Chip/Chip';
     5 +import ChipGroup from '../ChipGroup/ChipGroup';
     6 +import AvatarGroup from '../AvatarGroup/AvatarGroup';
     7 +import VulnerablePackage from '../VulnerablePackage/VulnerablePackage';
     8 +import { Icon } from '../Icon/Icon';
    7 9   
    8 10  export type CardProps = {
     11 + id: string;
    9 12   title: string;
    10 13   icon?: string;
    11 14   description?: string;
    skipped 9 lines
    21 24   name: string;
    22 25   moreCount?: number;
    23 26   };
    24  - variant?: 'to-all' | 'vulnerable' | string;
     27 + variant?: 'toAll' | 'vulnerable';
    25 28  };
    26 29   
    27 30  export default function Card({
    skipped 3 lines
    31 34   packageTags,
    32 35   featuredSites,
    33 36   vulnerablePackage,
    34  - variant = '',
     37 + variant,
    35 38  }: CardProps) {
    36 39   return (
    37  - <div className={clsx(styles.card, styles[variant])}>
     40 + <div className={clsx(styles.card, variant && styles[variant])}>
    38 41   <div className={styles.cardTop}>
    39 42   <header className={styles.header}>
    40 43   {icon && (
    41  - <div className={styles.icon}>
    42  - <img src={icon} alt='' />
     44 + <div className={styles.iconWrapper}>
     45 + <img className={styles.icon} src={icon} alt='' />
    43 46   </div>
    44 47   )}
    45 48   
    skipped 5 lines
    51 54   
    52 55   {variant === 'toAll' && (
    53 56   <button className={styles.arrowBtn} type='button'>
    54  - {/* TODO: properly import SVG arrow */}
    55  - <svg
    56  - width='24'
    57  - height='25'
    58  - viewBox='0 0 24 25'
    59  - fill='none'
    60  - xmlns='http://www.w3.org/2000/svg'
    61  - >
    62  - <path
    63  - d='M9 5.5L17 13L9 20.5'
    64  - stroke='#212121'
    65  - strokeWidth='2'
    66  - strokeLinecap='round'
    67  - strokeLinejoin='round'
    68  - />
    69  - </svg>
     57 + <Icon kind='arrow' color='#212121' width={10} height={18} />
    70 58   </button>
    71 59   )}
    72 60   
    73 61   {packageTags && (
    74 62   <div className={styles.tagsWrapper}>
    75  - <div className={styles.tags}>
    76  - {packageTags.featuredPackages.map((tag) => (
    77  - <Chip key={tag} size='large' font='monospace'>
    78  - {tag}
    79  - </Chip>
    80  - ))}
    81  - <Chip variant='outlined' size='large'>
     63 + <ChipGroup chips={packageTags.featuredPackages}>
     64 + <Chip className={styles.tag} variant='outlined' size='large'>
    82 65   +{packageTags.restPackages} packages
    83 66   </Chip>
    84  - </div>
     67 + </ChipGroup>
    85 68   </div>
    86 69   )}
    87 70   
    88 71   {featuredSites && (
    89  - <div className={styles.sitesWrapper}>
    90  - <div className={styles.sites}>
    91  - <div className={styles.sitesList}>
    92  - {featuredSites.iconList.map((featuredSite) => (
    93  - <div key={featuredSite} className={styles.sitesItem}>
    94  - <img src={featuredSite} alt='' />
    95  - </div>
    96  - ))}
    97  - </div>
    98  - 
    99  - <div className={styles.sitesCount}>
    100  - + {numberWithSpaces(featuredSites.numberOfUses)} sites use
    101  - </div>
    102  - </div>
    103  - </div>
     72 + <AvatarGroup avatarGroup={featuredSites.iconList} counter={featuredSites.numberOfUses} />
    104 73   )}
    105 74   
    106 75   {vulnerablePackage && (
    107  - <div className={styles.vulnerableWrapper}>
    108  - <span className={styles.vulnerablePackage}>
    109  - <span className={styles.vulnerableIcon}>
    110  - <Bug width='28' height='28' />
    111  - </span>
    112  - {vulnerablePackage.name}
    113  - </span>
    114  - {vulnerablePackage.moreCount && (
    115  - <span className={styles.vulnerableMore}>
    116  - <Chip variant='secondary' size='medium'>
    117  - +{vulnerablePackage.moreCount}
    118  - &nbsp;
    119  - <span className={styles.vulnerableMoreText}>more</span>
    120  - </Chip>
    121  - </span>
    122  - )}
    123  - </div>
     76 + <VulnerablePackage name={vulnerablePackage.name} moreTotal={vulnerablePackage.moreCount} />
    124 77   )}
    125 78   </div>
    126 79   );
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/CardGroup/CardGroup.module.scss
    1 1  @import '~styles/responsive.scss';
    2 2   
    3 3  .title {
     4 + margin-bottom: 36px;
     5 + 
    4 6   @include mobile-and-tablet {
    5 7   margin-bottom: 0;
    6 8   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/CardList/CardList.module.scss
    skipped 11 lines
    12 12   }
    13 13   
    14 14   @include mobile-and-tablet {
    15  - padding-top: 24px;
    16  - padding-bottom: 24px;
    17  - margin-left: -24px;
    18  - margin-right: -24px;
    19  - display: grid;
    20  - grid-gap: $mobile-gutter / 2;
    21  - //grid-template-columns: 8px repeat(var(--total), calc(50% - #{$mobile-gutter} * 2)) 8px;
    22  - grid-template-columns: 8px repeat(var(--total), 312px) 8px;
    23  - grid-template-rows: minmax(204px, 1fr);
     15 + margin-left: -20px;
     16 + margin-right: -20px;
     17 + padding: 24px 20px;
     18 + display: flex;
     19 + flex-wrap: nowrap;
    24 20   overflow-x: auto;
    25 21   scroll-snap-type: x proximity;
     22 + scroll-padding: 20px;
    26 23   
    27 24   &::-webkit-scrollbar {
    28 25   display: none;
    29 26   }
    30  - 
    31  - &::before,
    32  - &::after {
    33  - content: '';
    34  - }
    35 27   }
    36 28  }
    37 29   
    38 30  .vertical {
    39 31   @include mobile-and-tablet {
    40  - grid-template-columns: auto;
    41  - grid-template-rows: minmax(136px, 1fr);
     32 + flex-direction: column;
    42 33   overflow: initial;
    43 34   margin-left: 0;
    44 35   margin-right: 0;
    45  - 
    46  - &::before,
    47  - &::after {
    48  - display: none;
    49  - }
     36 + padding-left: 0;
     37 + padding-right: 0;
    50 38   }
    51 39  }
    52 40   
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/CardList/CardList.stories.tsx
    skipped 20 lines
    21 21  PopularSearchQueries.args = {
    22 22   cards: [
    23 23   {
     24 + id: 'uExBVGuF',
    24 25   title: 'github.com',
    25 26   icon: 'https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg',
    26 27   packageTags: {
    skipped 2 lines
    29 30   },
    30 31   },
    31 32   {
     33 + id: '1EkL1u5g',
    32 34   title: 'fingerprint.com',
    33 35   icon: 'https://avatars.githubusercontent.com/u/67208791?s=200&v=4',
    34 36   packageTags: {
    skipped 2 lines
    37 39   },
    38 40   },
    39 41   {
     42 + id: 'mhwO2bPM',
    40 43   title: 'facebook.com',
    41 44   icon: 'https://avatars.githubusercontent.com/u/69631?s=200&v=4',
    42 45   packageTags: {
    skipped 8 lines
    51 54  PopularPackages.args = {
    52 55   cards: [
    53 56   {
     57 + id: 'FPsBcl8R',
    54 58   title: '@team-griffin/react-heading-section',
    55 59   description: "This package's job is to automatically determine...",
    56 60   featuredSites: {
    skipped 6 lines
    63 67   },
    64 68   },
    65 69   {
     70 + id: 'emtYcsUh',
    66 71   title: 'unist-util-generated',
    67 72   description: 'unist utility to check if a node is generated',
    68 73   featuredSites: {
    skipped 6 lines
    75 80   },
    76 81   },
    77 82   {
     83 + id: 'TYIwvAfy',
    78 84   title: 'react-smooth',
    79 85   description: 'is a animation library work on React',
    80 86   featuredSites: {
    skipped 6 lines
    87 93   },
    88 94   },
    89 95   {
     96 + id: 'Lq1pEEX7',
    90 97   title: 'unist-util-position',
    91 98   description: 'unist utility to get the positional info of nodes',
    92 99   featuredSites: {
    skipped 6 lines
    99 106   },
    100 107   },
    101 108   {
     109 + id: 'cWOgIbmp',
    102 110   title: 'vfile-message',
    103 111   description: 'Create vfile messages',
    104 112   featuredSites: {
    skipped 6 lines
    111 119   },
    112 120   },
    113 121   {
     122 + id: 'UT97Vpoi',
    114 123   title: 'Go to all Popular packages',
    115 124   variant: 'toAll',
    116 125   },
    skipped 5 lines
    122 131   variant: 'vertical',
    123 132   cards: [
    124 133   {
     134 + id: 'LnO9Xynn',
    125 135   title: 'disneyland.omsk.ru/signup',
    126 136   vulnerablePackage: {
    127 137   name: 'mdast-util-from-markdown',
    skipped 1 lines
    129 139   variant: 'vulnerable',
    130 140   },
    131 141   {
     142 + id: '-A74UAy8',
    132 143   title: 'disneyland.omsk.ru/signup',
    133 144   vulnerablePackage: {
    134 145   name: 'mdast-util-from-markdown',
    skipped 2 lines
    137 148   variant: 'vulnerable',
    138 149   },
    139 150   {
     151 + id: 'DPa05I2W',
    140 152   title: 'disneyland.omsk.ru/signup',
    141 153   vulnerablePackage: {
    142 154   name: 'mdast-util-from-markdown',
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/CardList/CardList.tsx
    skipped 2 lines
    3 3  import Card, { CardProps } from '../Card/Card';
    4 4  import clsx from 'clsx';
    5 5   
    6  -export type CardListProps = {
     6 +type Props = {
    7 7   cards: CardProps[];
    8  - variant?: 'default' | 'vertical' | string;
     8 + variant?: 'default' | 'vertical';
    9 9  };
    10 10   
    11  -export default function CardList({ cards, variant = 'default' }: CardListProps) {
    12  - const style = { '--total': cards.length } as React.CSSProperties;
    13  - 
     11 +export default function CardList({ cards, variant = 'default' }: Props) {
    14 12   return (
    15  - <div className={clsx(styles.grid, styles[variant])} style={style}>
     13 + <div className={clsx(styles.grid, styles[variant])}>
    16 14   {cards.map((card) => (
    17  - <Card key={card.title} {...card} />
     15 + <Card key={card.id} {...card} />
    18 16   ))}
    19 17   </div>
    20 18   );
    skipped 2 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Chip/Chip.tsx
    skipped 3 lines
    4 4   
    5 5  export type ChipProps = {
    6 6   children: React.ReactNode;
     7 + className?: string;
    7 8   variant?: 'primary' | 'secondary' | 'outlined' | 'suggest' | string;
    8 9   size?: 'regular' | 'medium' | 'large' | string;
    9 10   font?: 'sans-serif' | 'monospace' | string;
    skipped 1 lines
    11 12   
    12 13  export default function Chip({
    13 14   children,
     15 + className,
    14 16   variant = 'primary',
    15 17   size = 'regular',
    16 18   font = 'sans-serif',
    17 19  }: ChipProps) {
    18 20   return (
    19  - <span className={clsx(styles.chip, styles[variant], styles[size], styles[font])}>
     21 + <span className={clsx(styles.chip, className, styles[variant], styles[size], styles[font])}>
    20 22   {children}
    21 23   </span>
    22 24   );
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/ChipGroup/ChipGroup.module.scss
     1 +@import '~styles/responsive.scss';
     2 + 
     3 +.tagsWrapper {
     4 + flex: 1;
     5 + display: flex;
     6 + flex-direction: column;
     7 +}
     8 + 
     9 +.tags {
     10 + display: flex;
     11 + flex-wrap: wrap;
     12 + align-items: center;
     13 + justify-content: flex-start;
     14 +}
     15 + 
     16 +.tag {
     17 + margin-bottom: 0.5rem;
     18 + 
     19 + &:not(:last-child) {
     20 + margin-right: 0.75rem;
     21 + }
     22 +}
     23 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/ChipGroup/ChipGroup.stories.tsx
     1 +import React from 'react';
     2 +import { ComponentStory, ComponentMeta } from '@storybook/react';
     3 +import ChipGroup from './ChipGroup';
     4 +import styles from '../Card/Card.module.scss';
     5 +import Chip from '../Chip/Chip';
     6 + 
     7 +export default {
     8 + title: 'Interface / ChipGroup',
     9 + component: ChipGroup,
     10 + parameters: {
     11 + layout: 'centered',
     12 + },
     13 +} as ComponentMeta<typeof ChipGroup>;
     14 + 
     15 +const Template: ComponentStory<typeof ChipGroup> = (args) => <ChipGroup {...args} />;
     16 + 
     17 +export const Default = Template.bind({});
     18 +Default.args = {
     19 + chips: ['mdast-util-from-markdown', 'react', 'react-dom'],
     20 +};
     21 + 
     22 +export const WithMoreCounter = Template.bind({});
     23 +const MoreCounter = (
     24 + <Chip className={styles.tag} variant='outlined' size='large'>
     25 + +45 packages
     26 + </Chip>
     27 +);
     28 +WithMoreCounter.args = {
     29 + chips: ['mdast-util-from-markdown', 'react', 'react-dom'],
     30 + children: MoreCounter,
     31 +};
     32 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/ChipGroup/ChipGroup.tsx
     1 +import React from 'react';
     2 +import styles from './ChipGroup.module.scss';
     3 +import Chip from '../Chip/Chip';
     4 + 
     5 +type Props = {
     6 + chips: string[];
     7 + children?: React.ReactNode;
     8 +};
     9 + 
     10 +// TODO: allow Chip customizing with props
     11 +export default function ChipGroup({ chips, children }: Props) {
     12 + return (
     13 + <div className={styles.tagsWrapper}>
     14 + <div className={styles.tags}>
     15 + {chips.map((chip) => (
     16 + <Chip key={chip} className={styles.tag} size='large' font='monospace'>
     17 + {chip}
     18 + </Chip>
     19 + ))}
     20 + 
     21 + {children}
     22 + </div>
     23 + </div>
     24 + );
     25 +}
     26 + 
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Container/Container.module.scss
     1 +@import '~styles/responsive.scss';
     2 + 
    1 3  .container {
    2 4   width: 100%;
    3  - max-width: 1376px;
    4  - padding-left: 20px;
    5  - padding-right: 20px;
     5 + max-width: 1470px;
     6 + padding-left: 52px;
     7 + padding-right: 52px;
    6 8   margin-left: auto;
    7 9   margin-right: auto;
     10 + 
     11 + @include xl {
     12 + padding-left: 20px;
     13 + padding-right: 20px;
     14 + }
    8 15  }
    9 16   
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/Header/Header.tsx
    skipped 12 lines
    13 13   <a
    14 14   href='https://github.com/gradejs/gradejs/discussions/6'
    15 15   target='_blank'
    16  - rel='norefferer noreferrer'
     16 + rel='noreferrer'
    17 17   className={styles.navLink}
    18 18   onClick={() => trackCustomEvent('ClickExternalLink', 'About')}
    19 19   >
    skipped 2 lines
    22 22   <a
    23 23   href='https://github.com/gradejs/gradejs/discussions'
    24 24   target='_blank'
    25  - rel='norefferer noreferrer'
     25 + rel='noreferrer'
    26 26   className={styles.navLink}
    27 27   onClick={() => trackCustomEvent('ClickExternalLink', 'Community')}
    28 28   >
    skipped 2 lines
    31 31   <a
    32 32   href='https://github.com/gradejs/gradejs'
    33 33   target='_blank'
    34  - rel='norefferer noreferrer'
     34 + rel='noreferrer'
    35 35   className={clsx(styles.navLink, styles.githubButton)}
    36 36   onClick={() => trackCustomEvent('ClickExternalLink', 'SourceCode')}
    37 37   >
    skipped 7 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/HeaderNew/HeaderNew.module.scss
    skipped 4 lines
    5 5   display: flex;
    6 6   align-items: center;
    7 7   justify-content: space-between;
    8  - padding: 42px 0;
     8 + padding: 44px 0;
    9 9   
    10 10   @include mobile-and-tablet {
    11 11   padding: 22px 0;
    skipped 1 lines
    13 13  }
    14 14   
    15 15  .logo {
     16 + display: flex;
     17 + width: 129px;
     18 + 
    16 19   @include mobile-and-tablet {
    17 20   width: 82px;
    18 21   }
    skipped 13 lines
    32 35  }
    33 36   
    34 37  .navLink {
     38 + display: flex;
    35 39   color: $white;
    36 40  }
    37 41   
    38 42  .githubIcon {
     43 + width: 32px;
     44 + height: 32px;
     45 + 
    39 46   @include mobile-and-tablet {
    40 47   width: 28px;
     48 + height: 28px;
    41 49   }
    42 50  }
    43 51   
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/HeaderNew/HeaderNew.tsx
    1 1  import React from 'react';
    2 2  import styles from './HeaderNew.module.scss';
    3 3  import Container from '../Container/Container';
    4  -import { Github, Logo } from 'components/icons';
     4 +import { Icon } from '../Icon/Icon';
    5 5  import { trackCustomEvent } from '../../../services/analytics';
    6 6   
    7 7  export default function HeaderNew() {
    8 8   return (
    9 9   <Container>
    10 10   <header className={styles.header}>
    11  - <Logo className={styles.logo} />
     11 + <a href='/' className={styles.logo}>
     12 + <Icon kind='logo' width={129} height={25} color='white' />
     13 + </a>
    12 14   <div className={styles.nav}>
    13 15   <a
    14 16   href='https://github.com/gradejs/gradejs/discussions/6'
    15 17   target='_blank'
    16  - rel='norefferer noreferrer'
     18 + rel='noreferrer'
    17 19   className={styles.navLink}
    18 20   onClick={() => trackCustomEvent('ClickExternalLink', 'About')}
    19 21   >
    skipped 2 lines
    22 24   <a
    23 25   href='https://github.com/gradejs/gradejs/discussions'
    24 26   target='_blank'
    25  - rel='norefferer noreferrer'
     27 + rel='noreferrer'
    26 28   className={styles.navLink}
    27 29   onClick={() => trackCustomEvent('ClickExternalLink', 'Community')}
    28 30   >
    skipped 2 lines
    31 33   <a
    32 34   href='https://github.com/gradejs/gradejs'
    33 35   target='_blank'
    34  - rel='norefferer noreferrer'
    35  - className={styles.githubLink}
     36 + rel='noreferrer'
     37 + className={styles.navLink}
    36 38   onClick={() => trackCustomEvent('ClickExternalLink', 'SourceCode')}
    37 39   >
    38  - <Github className={styles.githubIcon} width='32' height='32' color='#fff' />
     40 + <Icon
     41 + kind='githubLogo'
     42 + className={styles.githubIcon}
     43 + width={32}
     44 + height={32}
     45 + color='#fff'
     46 + />
    39 47   </a>
    40 48   </div>
    41 49   </header>
    skipped 4 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Hero/Hero.module.scss
    skipped 6 lines
    7 7   background-size: cover;
    8 8   color: $white;
    9 9   text-align: center;
     10 + 
     11 + @include mobile-and-tablet {
     12 + border-radius: 0 0 30px 30px;
     13 + }
    10 14  }
    11 15   
    12 16  .content {
    skipped 94 lines
    107 111   margin-left: 4px;
    108 112   
    109 113   @include mobile-and-tablet {
    110  - width: 20px;
    111  - height: 20px;
     114 + width: 10px;
     115 + height: 18px;
    112 116   }
    113 117  }
    114 118   
    skipped 27 lines
    142 146   display: inline-block;
    143 147   box-sizing: border-box;
    144 148   animation: rotation 1s linear infinite;
     149 + 
     150 + @include mobile-and-tablet {
     151 + width: 24px;
     152 + height: 24px;
     153 + border-width: 2px;
     154 + }
    145 155  }
    146 156   
    147 157  @keyframes rotation {
    skipped 8 lines
  • ■ ■ ■ ■ ■
    packages/web/src/components/ui/Hero/Hero.tsx
    skipped 1 lines
    2 2  import styles from './Hero.module.scss';
    3 3  import Container from '../Container/Container';
    4 4  import Chip from '../Chip/Chip';
    5  -import { Arrow } from '../../icons';
    6 5  import HeaderNew from '../HeaderNew/HeaderNew';
     6 +import { Icon } from '../Icon/Icon';
    7 7   
    8 8  export type HeroProps = {
    9 9   inputText?: string;
    skipped 24 lines
    34 34   <button type='submit' className={styles.submit}>
    35 35   {/* TODO: use SVG loading component */}
    36 36   {!loading ? (
    37  - <Arrow className={styles.submitIcon} width='32' height='32' color='#fff' />
     37 + <Icon
     38 + kind='arrow'
     39 + className={styles.submitIcon}
     40 + width={32}
     41 + height={32}
     42 + color='#fff'
     43 + />
    38 44   ) : (
    39 45   <span className={styles.loader} />
    40 46   )}
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/HighlightTech/HighlightTech.stories.tsx
    1 1  import React from 'react';
    2  -import webpackIcon from 'assets/icons/webpack.svg';
    3 2  import HighlightTech, { Props } from './HighlightTech';
    4 3   
    5 4  export default {
    skipped 8 lines
    14 13  Default.args = {
    15 14   description: 'Source build system',
    16 15   title: 'Webpack',
    17  - icon: webpackIcon,
    18 16  };
    19 17   
  • ■ ■ ■ ■
    packages/web/src/components/ui/Icon/Icon.tsx
    skipped 2 lines
    3 3  import grid from '../../../assets/icons/sprite/grid.svg';
    4 4  import lines from '../../../assets/icons/sprite/lines.svg';
    5 5  import external from '../../../assets/icons/sprite/external.svg';
     6 +import arrow from '../../../assets/icons/sprite/arrow.svg';
     7 +import bug from '../../../assets/icons/sprite/bug.svg';
     8 +import logo from '../../../assets/icons/sprite/logo.svg';
    6 9   
    7  -const icons = { githubLogo, grid, lines, external };
     10 +const icons = { githubLogo, grid, lines, external, arrow, bug, logo };
    8 11   
    9 12  export type IconProps = {
    10 13   kind: keyof typeof icons;
    skipped 31 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/Package/Package.tsx
    skipped 62 lines
    63 63   onClick={() => trackCustomEvent('Package', 'ClickRepoUrl')}
    64 64   className={styles.externalLink}
    65 65   >
    66  - <Icon kind={'githubLogo'} width={19} height={19} />
     66 + <Icon kind='githubLogo' width={19} height={19} />
    67 67   </a>
    68 68   )}
    69 69   {homepageUrl && homepageUrl !== repositoryUrl && (
    skipped 4 lines
    74 74   onClick={() => trackCustomEvent('Package', 'ClickHomepageUrl')}
    75 75   className={styles.externalLink}
    76 76   >
    77  - <Icon kind={'external'} width={19} height={19} />
     77 + <Icon kind='external' width={19} height={19} />
    78 78   </a>
    79 79   )}
    80 80   </div>
    skipped 46 lines
  • ■ ■ ■ ■
    packages/web/src/components/ui/Vulnerability/Vulnerability.tsx
    skipped 18 lines
    19 19   target='_blank'
    20 20   rel='noreferrer'
    21 21   >
    22  - <Icon kind={'external'} width={19} height={19} />
     22 + <Icon kind='external' width={19} height={19} />
    23 23   </a>
    24 24   )}
    25 25   
    skipped 42 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/VulnerablePackage/VulnerablePackage.module.scss
     1 +@import '~styles/_vars.scss';
     2 +@import '~styles/responsive.scss';
     3 + 
     4 +.vulnerableWrapper {
     5 + display: flex;
     6 + align-items: center;
     7 + margin-top: 16px;
     8 + margin-right: -9px;
     9 +}
     10 + 
     11 +.vulnerablePackage {
     12 + position: relative;
     13 + display: flex;
     14 + align-items: center;
     15 + font-size: 18px;
     16 + line-height: 24px;
     17 + font-family: $font-monospace;
     18 + color: $red-accent;
     19 + 
     20 + @include mobile-and-tablet {
     21 + font-size: 14px;
     22 + line-height: 20px;
     23 + }
     24 +}
     25 + 
     26 +.vulnerableIcon {
     27 + display: flex;
     28 + margin-right: 12px;
     29 +}
     30 + 
     31 +.vulnerableMore {
     32 + margin-left: 12px;
     33 +}
     34 + 
     35 +.vulnerableMoreText {
     36 + @include mobile-and-tablet {
     37 + display: none;
     38 + }
     39 +}
     40 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/components/ui/VulnerablePackage/VulnerablePackage.tsx
     1 +import React from 'react';
     2 +import styles from './VulnerablePackage.module.scss';
     3 +import { Icon } from '../Icon/Icon';
     4 +import Chip from '../Chip/Chip';
     5 + 
     6 +type Props = {
     7 + name: string;
     8 + moreTotal?: number;
     9 +};
     10 + 
     11 +export default function VulnerablePackage({ name, moreTotal }: Props) {
     12 + return (
     13 + <div className={styles.vulnerableWrapper}>
     14 + <span className={styles.vulnerablePackage}>
     15 + <span className={styles.vulnerableIcon}>
     16 + <Icon kind='bug' color='#F3512E' width={28} height={28} />
     17 + </span>
     18 + {name}
     19 + </span>
     20 + {moreTotal && (
     21 + <span className={styles.vulnerableMore}>
     22 + <Chip variant='secondary' size='medium'>
     23 + +{moreTotal}
     24 + &nbsp;
     25 + <span className={styles.vulnerableMoreText}>more</span>
     26 + </Chip>
     27 + </span>
     28 + )}
     29 + </div>
     30 + );
     31 +}
     32 + 
  • ■ ■ ■ ■ ■ ■
    packages/web/src/styles/global.scss
    skipped 24 lines
    25 25   }
    26 26  }
    27 27   
     28 +button,
     29 +input,
     30 +optgroup,
     31 +select,
     32 +textarea {
     33 + margin: 0;
     34 + font-family: inherit;
     35 + font-size: inherit;
     36 + line-height: inherit;
     37 +}
     38 + 
    28 39  code,
    29 40  kbd,
    30 41  pre,
    skipped 80 lines
  • ■ ■ ■ ■ ■ ■
    packages/web/src/utils/helpers.tsx
    1  -export function numberWithSpaces(x: number) {
    2  - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
     1 +export function formatNumber(x: number) {
     2 + return x.toLocaleString();
    3 3  }
    4 4   
Please wait...
Page is in error, reload to recover