vitess.io/vitess@v0.16.2/web/vtadmin/src/components/routes/Settings.tsx (about)

     1  import * as React from 'react';
     2  import { useDocumentTitle } from '../../hooks/useDocumentTitle';
     3  import { Theme, useTheme } from '../../hooks/useTheme';
     4  import { Icon, Icons } from '../Icon';
     5  import { Select } from '../inputs/Select';
     6  import { Intent } from '../intent';
     7  import { ContentContainer } from '../layout/ContentContainer';
     8  import { warn, danger, success, info } from '../Snackbar';
     9  import { Tab } from '../tabs/Tab';
    10  import { TabContainer } from '../tabs/TabContainer';
    11  import { TextInput } from '../TextInput';
    12  import Toggle from '../toggle/Toggle';
    13  import { Tooltip } from '../tooltip/Tooltip';
    14  import { env } from '../../util/env';
    15  import style from './Settings.module.scss';
    16  
    17  /* eslint-disable jsx-a11y/anchor-is-valid */
    18  export const Settings = () => {
    19      useDocumentTitle('Debug');
    20      const [theme, setTheme] = useTheme();
    21      const [formData, setFormData] = React.useState<{ [key: string]: any }>({});
    22      const [enabled, setEnabled] = React.useState(false);
    23  
    24      return (
    25          <ContentContainer>
    26              <div className={style.container}>
    27                  <h1 className="mt-8">Settings</h1>
    28  
    29                  <h2 className="mt-12 mb-8">Environment variables</h2>
    30                  <pre>{JSON.stringify(env(), null, 2)}</pre>
    31  
    32                  {process.env.NODE_ENV !== 'production' && (
    33                      <>
    34                          <h2 className="mt-12 mb-8">Style Guide</h2>
    35  
    36                          <section>
    37                              <h3 className="mt-12 mb-8">Theme</h3>
    38                              <div>
    39                                  {Object.values(Theme).map((t) => (
    40                                      <div key={t}>
    41                                          <label>
    42                                              <input
    43                                                  checked={theme === t}
    44                                                  name="theme"
    45                                                  onChange={() => setTheme(t)}
    46                                                  type="radio"
    47                                                  value={t}
    48                                              />
    49                                              {t}
    50                                          </label>
    51                                      </div>
    52                                  ))}
    53                              </div>
    54                          </section>
    55  
    56                          <section>
    57                              <h3 className="mt-12 mb-8">Colours</h3>
    58                              {[
    59                                  [style.danger, style.danger50, style.danger200],
    60                                  [style.success, style.success50, style.success200],
    61                                  [style.warning, style.warning50, style.warning200],
    62                                  [style.vtblue, style.vtblue50, style.vtblue200],
    63                                  [style.vtblueDark, style.vtblueDark50, style.vtblueDark200],
    64                                  [
    65                                      style.gray75,
    66                                      style.gray100,
    67                                      style.gray200,
    68                                      style.gray400,
    69                                      style.gray600,
    70                                      style.gray800,
    71                                      style.gray900,
    72                                  ],
    73                              ].map((colors, idx) => {
    74                                  return (
    75                                      <div className="flex my-8" key={idx}>
    76                                          {colors.map((c) => (
    77                                              <div className={`${c} mr-4 font-semibold text-sm`} key={c}>
    78                                                  <div className="w-40 h-16 rounded" />
    79                                              </div>
    80                                          ))}
    81                                      </div>
    82                                  );
    83                              })}
    84                          </section>
    85  
    86                          <section>
    87                              <h3 className="mt-12 mb-8">Typography</h3>
    88  
    89                              <div className="my-16">
    90                                  <p className="text-sm">The quick brown fox ...</p>
    91                                  <p className="text-base">The quick brown fox ...</p>
    92                                  <p className="text-lg">The quick brown fox ...</p>
    93                                  <p className="text-xl">The quick brown fox ...</p>
    94                                  <p className="text-2xl">The quick brown fox ...</p>
    95                                  <p className="text-3xl">The quick brown fox ...</p>
    96                              </div>
    97  
    98                              <div className="my-16">
    99                                  <p className="text-sm font-mono">The quick brown fox ...</p>
   100                                  <p className="text-base font-mono">The quick brown fox ...</p>
   101                                  <p className="text-lg font-mono">The quick brown fox ...</p>
   102                                  <p className="text-xl font-mono">The quick brown fox ...</p>
   103                                  <p className="text-2xl font-mono">The quick brown fox ...</p>
   104                                  <p className="text-3xl font-mono">The quick brown fox ...</p>
   105                              </div>
   106  
   107                              <div className="max-w-prose my-16">
   108                                  <p>
   109                                      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi in facilisis libero,
   110                                      eget congue lorem. Nulla non ligula eget erat aliquam lacinia a eget felis. Nulla
   111                                      turpis sapien, ultricies sit amet suscipit quis, auctor id risus. Donec pellentesque
   112                                      tellus metus, in eleifend lacus euismod eget. Vestibulum vehicula ut metus id
   113                                      vestibulum. Nam vulputate sapien sit amet tempor efficitur. Donec dictum tellus nec
   114                                      leo fringilla, eu tempor neque posuere. Integer porta, velit quis interdum
   115                                      ultricies, quam enim suscipit eros, quis ornare metus ante vitae est. Sed quis
   116                                      dignissim justo, at ultrices urna. Suspendisse gravida, tortor sed semper tristique,
   117                                      erat metus vulputate augue, quis tempor mi nisi vitae magna. Donec auctor fermentum
   118                                      magna, ut feugiat odio tincidunt sit amet. Donec accumsan lorem mi, ut placerat ex
   119                                      lacinia vel. Nullam ut magna feugiat, ornare nibh vel, tincidunt nisi. Fusce
   120                                      tincidunt malesuada posuere.
   121                                  </p>
   122  
   123                                  <p>
   124                                      Cras elementum lacinia tristique. Vestibulum nec sem sit amet velit lobortis
   125                                      accumsan ut eget lacus. Nulla eros ipsum, pellentesque sed vehicula id, pulvinar ut
   126                                      dolor. Proin facilisis ligula vel faucibus iaculis. Donec venenatis massa lorem, sed
   127                                      tempus libero vulputate nec. Vestibulum semper nibh id tortor dapibus, a
   128                                      pellentesque libero porttitor. Pellentesque id elit nulla. Duis congue hendrerit
   129                                      rhoncus. Vivamus accumsan tincidunt augue in sollicitudin. Cras sed augue eget elit
   130                                      semper interdum tristique at ligula. Aliquam vel pretium sem. Donec egestas nisi
   131                                      blandit congue pretium.
   132                                  </p>
   133  
   134                                  <p>
   135                                      Duis vulputate blandit ante nec bibendum. Duis ipsum augue, tempus et viverra et,
   136                                      ultricies ac sapien. Nullam vel laoreet turpis, in convallis eros. Suspendisse sit
   137                                      amet magna turpis. Curabitur mi risus, facilisis vel fringilla ut, facilisis nec
   138                                      tortor. Mauris rutrum vehicula justo ac dapibus. Sed aliquam, eros non bibendum
   139                                      sodales, mauris est iaculis dui, ut tristique nibh sapien ac sapien. Lorem ipsum
   140                                      dolor sit amet, consectetur adipiscing elit.
   141                                  </p>
   142                              </div>
   143                          </section>
   144  
   145                          <section>
   146                              <h3 className="mt-12 mb-8">Tabs</h3>
   147  
   148                              <TabContainer className={style.tabContainer} size="small">
   149                                  <Tab text="Small Tab" to="/debug/small/1" />
   150                                  <Tab text="Small Tab" to="/debug/small/2" count={1} />
   151                                  <Tab text="Small Tab" to="/debug/small/3" status="danger" />
   152                              </TabContainer>
   153  
   154                              <TabContainer className={style.tabContainer} size="medium">
   155                                  <Tab text="Medium Tab" to="/debug/medium/1" />
   156                                  <Tab text="Medium Tab" to="/debug/medium/2" status="success" count={1000} />
   157                                  <Tab text="Medium Tab" to="/debug/medium/3" />
   158                              </TabContainer>
   159  
   160                              <TabContainer className={style.tabContainer} size="large">
   161                                  <Tab text="Large Tab" to="/debug/large/1" />
   162                                  <Tab text="Large Tab" to="/debug/large/2" status="primary" />
   163                                  <Tab text="Large Tab" to="/debug/large/3" count={10000} />
   164                              </TabContainer>
   165                          </section>
   166  
   167                          <section>
   168                              <h3 className="mt-12 mb-8">Icons</h3>
   169                              <div className={style.iconContainer}>
   170                                  {Object.values(Icons).map((i) => (
   171                                      <Tooltip text={i}>
   172                                          <Icon className={style.icon} icon={i} key={i} tabIndex={0} />
   173                                      </Tooltip>
   174                                  ))}
   175                              </div>
   176                          </section>
   177                          <section>
   178                              <h3 className="mt-12 mb-8">Toggle</h3>
   179                              <Toggle enabled={enabled} onChange={() => setEnabled(!enabled)} />
   180                          </section>
   181                          <section>
   182                              <h3 className="mt-12 mb-8">Select</h3>
   183                              <div className={style.dropdownContainer}>
   184                                  <div className={style.dropdownRow}>
   185                                      <Select
   186                                          itemToString={(fruit) => fruit?.name || ''}
   187                                          items={FRUITS}
   188                                          label="Fruits"
   189                                          onChange={(fruit) => setFormData({ ...formData, selectFruitDefault: fruit })}
   190                                          placeholder="Choose a fruit"
   191                                          renderItem={(fruit) => `${fruit.emoji} ${fruit.name}`}
   192                                          selectedItem={formData.selectFruitDefault || null}
   193                                      />
   194                                      <Select
   195                                          items={FRUIT_NAMES}
   196                                          label="Fruit names"
   197                                          onChange={(fruitName) =>
   198                                              setFormData({ ...formData, selectFruitNameDefault: fruitName })
   199                                          }
   200                                          placeholder="Choose a fruit name"
   201                                          selectedItem={formData.selectFruitNameDefault || null}
   202                                      />
   203                                      <Select
   204                                          disabled
   205                                          itemToString={(fruit) => fruit?.name || ''}
   206                                          items={FRUITS}
   207                                          label="Fruits"
   208                                          onChange={(fruit) => setFormData({ ...formData, selectFruitDefault: fruit })}
   209                                          placeholder="Choose a fruit"
   210                                          renderItem={(fruit) => `${fruit.emoji} ${fruit.name}`}
   211                                          selectedItem={formData.selectFruitDefault || null}
   212                                      />
   213                                      <Select
   214                                          items={[]}
   215                                          emptyPlaceholder="No fruits :("
   216                                          label="Empty Fruits"
   217                                          onChange={(fruit) => setFormData({ ...formData, selectFruitDefault: fruit })}
   218                                          placeholder="Choose a fruit"
   219                                          renderItem={(fruit) => `${fruit.emoji} ${fruit.name}`}
   220                                          selectedItem={formData.selectFruitDefault || null}
   221                                      />
   222                                  </div>
   223                                  <div className={style.dropdownRow}>
   224                                      <Select
   225                                          itemToString={(fruit) => fruit?.name || ''}
   226                                          items={FRUITS}
   227                                          label="Fruits"
   228                                          onChange={(fruit) => setFormData({ ...formData, selectFruitLarge: fruit })}
   229                                          placeholder="Choose a fruit"
   230                                          renderItem={(fruit) => `${fruit.emoji} ${fruit.name}`}
   231                                          selectedItem={formData.selectFruitLarge || null}
   232                                          size="large"
   233                                      />
   234                                      <Select
   235                                          items={FRUIT_NAMES}
   236                                          label="Fruit names"
   237                                          onChange={(fruitName) =>
   238                                              setFormData({ ...formData, selectFruitNameLarge: fruitName })
   239                                          }
   240                                          placeholder="Choose a fruit name"
   241                                          size="large"
   242                                          selectedItem={formData.selectFruitNameLarge || null}
   243                                      />
   244                                      <Select
   245                                          disabled
   246                                          itemToString={(fruit) => fruit?.name || ''}
   247                                          items={FRUITS}
   248                                          label="Fruits"
   249                                          onChange={(fruit) => setFormData({ ...formData, selectFruitLarge: fruit })}
   250                                          placeholder="Choose a fruit"
   251                                          renderItem={(fruit) => `${fruit.emoji} ${fruit.name}`}
   252                                          selectedItem={formData.selectFruitLarge || null}
   253                                          size="large"
   254                                      />
   255                                  </div>
   256                              </div>
   257                          </section>
   258  
   259                          <section>
   260                              <h3 className="mt-12 mb-8">Text Inputs</h3>
   261                              <div className={style.inputContainer}>
   262                                  <TextInput placeholder="Basic text input" />
   263                                  <TextInput iconLeft={Icons.search} placeholder="With leftIcon" />
   264                                  <TextInput iconRight={Icons.delete} placeholder="With rightIcon" />
   265                                  <TextInput
   266                                      iconLeft={Icons.search}
   267                                      iconRight={Icons.delete}
   268                                      placeholder="With leftIcon and rightIcon"
   269                                  />
   270                                  <TextInput disabled placeholder="Disabled" />
   271                                  <TextInput
   272                                      disabled
   273                                      iconLeft={Icons.search}
   274                                      iconRight={Icons.delete}
   275                                      placeholder="Disabled with icons"
   276                                  />
   277                                  <div className={style.inputRow}>
   278                                      <TextInput
   279                                          iconLeft={Icons.search}
   280                                          iconRight={Icons.delete}
   281                                          size="large"
   282                                          placeholder="Button-adjacent"
   283                                      />
   284                                      <button className="btn btn-lg" type="button">
   285                                          Primary
   286                                      </button>
   287                                      <button className="btn btn-lg btn-secondary" type="button">
   288                                          Secondary
   289                                      </button>
   290                                  </div>
   291                                  <div className={style.inputRow}>
   292                                      <TextInput
   293                                          iconLeft={Icons.search}
   294                                          iconRight={Icons.delete}
   295                                          placeholder="Button-adjacent"
   296                                      />
   297                                      <button className="btn" type="button">
   298                                          Primary
   299                                      </button>
   300                                      <button className="btn btn-secondary" type="button">
   301                                          Secondary
   302                                      </button>
   303                                  </div>
   304                              </div>
   305                          </section>
   306  
   307                          <section>
   308                              <h3 className="mt-12 mb-8">Buttons</h3>
   309  
   310                              {['btn-lg', '', 'btn-sm'].map((s, idx) => {
   311                                  return (
   312                                      <div className="my-16">
   313                                          {['', 'btn-danger', 'btn-warning', 'btn-success'].map((v) => {
   314                                              return (
   315                                                  <div className="flex gap-4 my-6" key={`${idx}-${v}`}>
   316                                                      <button className={`btn ${s} ${v}`}>Button</button>
   317                                                      <a className={`btn ${s} ${v}`} href="#">
   318                                                          Link
   319                                                      </a>
   320  
   321                                                      <button className={`btn ${s} ${v} btn-secondary`}>Button</button>
   322                                                      <a className={`btn ${s} ${v} btn-secondary`} href="#">
   323                                                          Link
   324                                                      </a>
   325  
   326                                                      <button className={`btn ${s} ${v} btn-secondary`}>
   327                                                          <Icon icon={Icons.circleAdd} />
   328                                                          Button
   329                                                      </button>
   330                                                      <a className={`btn ${s} ${v} btn-secondary`} href="#">
   331                                                          <Icon icon={Icons.circleAdd} />
   332                                                          Link
   333                                                      </a>
   334  
   335                                                      <button className={`btn ${s} ${v}`} disabled>
   336                                                          Button
   337                                                      </button>
   338                                                      <button className={`btn ${s} ${v} btn-secondary`} disabled>
   339                                                          <Icon icon={Icons.circleAdd} />
   340                                                          Button
   341                                                      </button>
   342                                                  </div>
   343                                              );
   344                                          })}
   345                                      </div>
   346                                  );
   347                              })}
   348                          </section>
   349                          <section>
   350                              <Snackbars />
   351                          </section>
   352                      </>
   353                  )}
   354              </div>
   355          </ContentContainer>
   356      );
   357  };
   358  
   359  const Snackbars: React.FC = () => {
   360      const intents = Object.keys(Intent);
   361      return (
   362          <div>
   363              <h3 className="mt-12 mb-8">Snackbars</h3>
   364  
   365              {intents.map((i) => {
   366                  const onClick = () => {
   367                      switch (i) {
   368                          case 'danger':
   369                              danger('This is a danger snackbar.');
   370                              break;
   371                          case 'success':
   372                              success('This is a success snackbar.');
   373                              break;
   374                          case 'none':
   375                              info('This is an info snackbar.');
   376                              break;
   377                          case 'warning':
   378                              warn('This is a warn snackbar with a very very very very very very very long message.');
   379                              break;
   380                      }
   381                  };
   382                  return (
   383                      <button onClick={onClick} className={`btn btn-secondary mr-2`} key={i}>
   384                          {i}
   385                      </button>
   386                  );
   387              })}
   388          </div>
   389      );
   390  };
   391  
   392  const FRUITS: { emoji: string; name: string; id: string }[] = [
   393      { emoji: '🍎', name: 'apple (red)', id: 'red_apple' },
   394      { emoji: '🍏', name: 'apple (green)', id: 'green_apple' },
   395      { emoji: '🍌', name: 'banana', id: 'banana' },
   396      { emoji: '🍒', name: 'cherry', id: 'cherry' },
   397      { emoji: '🥥', name: 'coconut', id: 'coconut' },
   398      { emoji: '🍇', name: 'grape', id: 'grape' },
   399      { emoji: '🥝', name: 'kiwi', id: 'kiwi' },
   400      { emoji: '🍋', name: 'lemon', id: 'lemon' },
   401      { emoji: '🍈', name: 'melon', id: 'melon' },
   402      { emoji: '🍊', name: 'orange', id: 'orange' },
   403      { emoji: '🍑', name: 'peach', id: 'peach' },
   404      { emoji: '🍐', name: 'pear', id: 'pear' },
   405      { emoji: '🍍', name: 'pineapple', id: 'pineapple' },
   406      { emoji: '🍓', name: 'strawberry', id: 'strawberry' },
   407      { emoji: '🍉', name: 'watermelon', id: 'watermelon' },
   408  ];
   409  
   410  const FRUIT_NAMES = FRUITS.map((f) => f.name).slice(0, 5);