瀏覽代碼

Add theme

Alexander 3 年之前
父節點
當前提交
6b2c6dba00

+ 71 - 67
kafka-ui-react-app/src/components/App.tsx

@@ -11,6 +11,8 @@ import ClusterPage from 'components/Cluster/Cluster';
 import Version from 'components/Version/Version';
 import Alert from 'components/Alert/Alert';
 import 'components/App.scss';
+import { ThemeProvider } from 'styled-components';
+import theme from 'theme/theme';
 
 export interface AppProps {
   isClusterListFetched?: boolean;
@@ -45,81 +47,83 @@ const App: React.FC<AppProps> = ({
   }, [fetchClustersList]);
 
   return (
-    <div
-      className={cx('Layout', { 'Layout--sidebarVisible': isSidebarVisible })}
-    >
-      <nav
-        className="navbar is-fixed-top is-white Layout__header"
-        role="navigation"
-        aria-label="main navigation"
+    <ThemeProvider theme={theme}>
+      <div
+        className={cx('Layout', { 'Layout--sidebarVisible': isSidebarVisible })}
       >
-        <div className="navbar-brand">
-          <div
-            className={cx('navbar-burger', 'ml-0', {
-              'is-active': isSidebarVisible,
-            })}
-            onClick={onBurgerClick}
-            onKeyDown={onBurgerClick}
-            role="button"
-            tabIndex={0}
-          >
-            <span />
-            <span />
-            <span />
-          </div>
+        <nav
+          className="navbar is-fixed-top is-white Layout__header"
+          role="navigation"
+          aria-label="main navigation"
+        >
+          <div className="navbar-brand">
+            <div
+              className={cx('navbar-burger', 'ml-0', {
+                'is-active': isSidebarVisible,
+              })}
+              onClick={onBurgerClick}
+              onKeyDown={onBurgerClick}
+              role="button"
+              tabIndex={0}
+            >
+              <span />
+              <span />
+              <span />
+            </div>
 
-          <a className="navbar-item title is-5 is-marginless" href="/ui">
-            UI for Apache Kafka
-          </a>
+            <a className="navbar-item title is-5 is-marginless" href="/ui">
+              UI for Apache Kafka
+            </a>
 
-          <div className="navbar-item">
-            <Version tag={GIT_TAG} commit={GIT_COMMIT} />
+            <div className="navbar-item">
+              <Version tag={GIT_TAG} commit={GIT_COMMIT} />
+            </div>
           </div>
-        </div>
-      </nav>
+        </nav>
 
-      <main className="Layout__container">
-        <div className="Layout__sidebar has-shadow has-background-white">
-          <Nav
-            clusters={clusters}
-            isClusterListFetched={isClusterListFetched}
-          />
-        </div>
-        <div
-          className="Layout__sidebarOverlay is-overlay"
-          onClick={closeSidebar}
-          onKeyDown={closeSidebar}
-          tabIndex={-1}
-          aria-hidden="true"
-        />
-        {isClusterListFetched ? (
-          <Switch>
-            <Route
-              exact
-              path={['/', '/ui', '/ui/clusters']}
-              component={Dashboard}
+        <main className="Layout__container">
+          <div className="Layout__sidebar has-shadow has-background-white">
+            <Nav
+              clusters={clusters}
+              isClusterListFetched={isClusterListFetched}
             />
-            <Route path="/ui/clusters/:clusterName" component={ClusterPage} />
-          </Switch>
-        ) : (
-          <PageLoader fullHeight />
-        )}
-      </main>
-
-      <div className="Layout__alerts">
-        {alerts.map(({ id, type, title, message, response, createdAt }) => (
-          <Alert
-            key={id}
-            id={id}
-            type={type}
-            title={title}
-            message={message}
-            response={response}
-            createdAt={createdAt}
+          </div>
+          <div
+            className="Layout__sidebarOverlay is-overlay"
+            onClick={closeSidebar}
+            onKeyDown={closeSidebar}
+            tabIndex={-1}
+            aria-hidden="true"
           />
-        ))}
+          {isClusterListFetched ? (
+            <Switch>
+              <Route
+                exact
+                path={['/', '/ui', '/ui/clusters']}
+                component={Dashboard}
+              />
+              <Route path="/ui/clusters/:clusterName" component={ClusterPage} />
+            </Switch>
+          ) : (
+            <PageLoader fullHeight />
+          )}
+        </main>
+
+        <div className="Layout__alerts">
+          {alerts.map(({ id, type, title, message, response, createdAt }) => (
+            <Alert
+              key={id}
+              id={id}
+              type={type}
+              title={title}
+              message={message}
+              response={response}
+              createdAt={createdAt}
+            />
+          ))}
+        </div>
       </div>
-    </div>
+    </ThemeProvider>
   );
 };
 

+ 307 - 262
kafka-ui-react-app/src/components/__tests__/__snapshots__/App.spec.tsx.snap

@@ -53,163 +53,171 @@ exports[`App view matches snapshot 1`] = `
         }
         isClusterListFetched={true}
       >
-        <div
-          className="Layout"
+        <Component
+          theme={
+            Object {
+              "buttonStyles": Object {
+                "fontSize": Object {
+                  "L": "16px",
+                  "M": "14px",
+                  "S": "14px",
+                },
+                "height": Object {
+                  "L": "40px",
+                  "M": "32px",
+                  "S": "24px",
+                },
+                "primary": Object {
+                  "backgroundColor": Object {
+                    "active": "#1414B8",
+                    "hover": "#1717CF",
+                    "normal": "#4F4FFF",
+                  },
+                  "color": "#FFFFFF",
+                  "invertedColors": Object {
+                    "active": "#1414B8",
+                    "hover": "#1717CF",
+                    "normal": "#4F4FFF",
+                  },
+                },
+                "secondary": Object {
+                  "backgroundColor": Object {
+                    "active": "#D5DADD",
+                    "hover": "#E3E6E8",
+                    "normal": "#F1F2F3",
+                  },
+                  "color": "#171A1C",
+                  "invertedColors": Object {
+                    "active": "#171A1C",
+                    "hover": "#454F54",
+                    "normal": "#73848C",
+                  },
+                },
+              },
+            }
+          }
         >
-          <nav
-            aria-label="main navigation"
-            className="navbar is-fixed-top is-white Layout__header"
-            role="navigation"
+          <div
+            className="Layout"
           >
-            <div
-              className="navbar-brand"
+            <nav
+              aria-label="main navigation"
+              className="navbar is-fixed-top is-white Layout__header"
+              role="navigation"
             >
               <div
-                className="navbar-burger ml-0"
-                onClick={[Function]}
-                onKeyDown={[Function]}
-                role="button"
-                tabIndex={0}
-              >
-                <span />
-                <span />
-                <span />
-              </div>
-              <a
-                className="navbar-item title is-5 is-marginless"
-                href="/ui"
-              >
-                UI for Apache Kafka
-              </a>
-              <div
-                className="navbar-item"
+                className="navbar-brand"
               >
-                <Version />
+                <div
+                  className="navbar-burger ml-0"
+                  onClick={[Function]}
+                  onKeyDown={[Function]}
+                  role="button"
+                  tabIndex={0}
+                >
+                  <span />
+                  <span />
+                  <span />
+                </div>
+                <a
+                  className="navbar-item title is-5 is-marginless"
+                  href="/ui"
+                >
+                  UI for Apache Kafka
+                </a>
+                <div
+                  className="navbar-item"
+                >
+                  <Version />
+                </div>
               </div>
-            </div>
-          </nav>
-          <main
-            className="Layout__container"
-          >
-            <div
-              className="Layout__sidebar has-shadow has-background-white"
+            </nav>
+            <main
+              className="Layout__container"
             >
-              <Nav
-                clusters={Array []}
-                isClusterListFetched={true}
+              <div
+                className="Layout__sidebar has-shadow has-background-white"
               >
-                <aside
-                  className="menu has-shadow has-background-white"
+                <Nav
+                  clusters={Array []}
+                  isClusterListFetched={true}
                 >
-                  <p
-                    className="menu-label"
-                  >
-                    General
-                  </p>
-                  <ul
-                    className="menu-list"
+                  <aside
+                    className="menu has-shadow has-background-white"
                   >
-                    <li>
-                      <NavLink
-                        activeClassName="is-active"
-                        exact={true}
-                        title="Dashboard"
-                        to="/ui"
-                      >
-                        <Link
-                          aria-current={null}
+                    <p
+                      className="menu-label"
+                    >
+                      General
+                    </p>
+                    <ul
+                      className="menu-list"
+                    >
+                      <li>
+                        <NavLink
+                          activeClassName="is-active"
+                          exact={true}
                           title="Dashboard"
-                          to={
-                            Object {
-                              "hash": "",
-                              "pathname": "/ui",
-                              "search": "",
-                              "state": null,
-                            }
-                          }
+                          to="/ui"
                         >
-                          <LinkAnchor
+                          <Link
                             aria-current={null}
-                            href="/ui"
-                            navigate={[Function]}
                             title="Dashboard"
+                            to={
+                              Object {
+                                "hash": "",
+                                "pathname": "/ui",
+                                "search": "",
+                                "state": null,
+                              }
+                            }
                           >
-                            <a
+                            <LinkAnchor
                               aria-current={null}
                               href="/ui"
-                              onClick={[Function]}
+                              navigate={[Function]}
                               title="Dashboard"
                             >
-                              Dashboard
-                            </a>
-                          </LinkAnchor>
-                        </Link>
-                      </NavLink>
-                    </li>
-                  </ul>
-                  <p
-                    className="menu-label"
-                  >
-                    Clusters
-                  </p>
-                </aside>
-              </Nav>
-            </div>
-            <div
-              aria-hidden="true"
-              className="Layout__sidebarOverlay is-overlay"
-              onClick={[Function]}
-              onKeyDown={[Function]}
-              tabIndex={-1}
-            />
-            <Switch>
-              <Route
-                component={[Function]}
-                computedMatch={
-                  Object {
-                    "isExact": true,
-                    "params": Object {},
-                    "path": "/",
-                    "url": "/",
-                  }
-                }
-                exact={true}
-                location={
-                  Object {
-                    "hash": "",
-                    "pathname": "/",
-                    "search": "",
-                    "state": undefined,
-                  }
-                }
-                path={
-                  Array [
-                    "/",
-                    "/ui",
-                    "/ui/clusters",
-                  ]
-                }
-              >
-                <Dashboard
-                  history={
+                              <a
+                                aria-current={null}
+                                href="/ui"
+                                onClick={[Function]}
+                                title="Dashboard"
+                              >
+                                Dashboard
+                              </a>
+                            </LinkAnchor>
+                          </Link>
+                        </NavLink>
+                      </li>
+                    </ul>
+                    <p
+                      className="menu-label"
+                    >
+                      Clusters
+                    </p>
+                  </aside>
+                </Nav>
+              </div>
+              <div
+                aria-hidden="true"
+                className="Layout__sidebarOverlay is-overlay"
+                onClick={[Function]}
+                onKeyDown={[Function]}
+                tabIndex={-1}
+              />
+              <Switch>
+                <Route
+                  component={[Function]}
+                  computedMatch={
                     Object {
-                      "action": "POP",
-                      "block": [Function],
-                      "createHref": [Function],
-                      "go": [Function],
-                      "goBack": [Function],
-                      "goForward": [Function],
-                      "listen": [Function],
-                      "location": Object {
-                        "hash": "",
-                        "pathname": "/",
-                        "search": "",
-                        "state": undefined,
-                      },
-                      "push": [Function],
-                      "replace": [Function],
+                      "isExact": true,
+                      "params": Object {},
+                      "path": "/",
+                      "url": "/",
                     }
                   }
+                  exact={true}
                   location={
                     Object {
                       "hash": "",
@@ -218,164 +226,201 @@ exports[`App view matches snapshot 1`] = `
                       "state": undefined,
                     }
                   }
-                  match={
-                    Object {
-                      "isExact": true,
-                      "params": Object {},
-                      "path": "/",
-                      "url": "/",
-                    }
+                  path={
+                    Array [
+                      "/",
+                      "/ui",
+                      "/ui/clusters",
+                    ]
                   }
-                  staticContext={Object {}}
                 >
-                  <div
-                    className="section"
+                  <Dashboard
+                    history={
+                      Object {
+                        "action": "POP",
+                        "block": [Function],
+                        "createHref": [Function],
+                        "go": [Function],
+                        "goBack": [Function],
+                        "goForward": [Function],
+                        "listen": [Function],
+                        "location": Object {
+                          "hash": "",
+                          "pathname": "/",
+                          "search": "",
+                          "state": undefined,
+                        },
+                        "push": [Function],
+                        "replace": [Function],
+                      }
+                    }
+                    location={
+                      Object {
+                        "hash": "",
+                        "pathname": "/",
+                        "search": "",
+                        "state": undefined,
+                      }
+                    }
+                    match={
+                      Object {
+                        "isExact": true,
+                        "params": Object {},
+                        "path": "/",
+                        "url": "/",
+                      }
+                    }
+                    staticContext={Object {}}
                   >
                     <div
-                      className="level"
+                      className="section"
                     >
                       <div
-                        className="level-item level-left"
+                        className="level"
                       >
-                        <Breadcrumb>
-                          <nav
-                            aria-label="breadcrumbs"
-                            className="breadcrumb"
-                          >
-                            <ul>
-                              <li
-                                className="is-active"
-                              >
-                                <span
-                                  className=""
+                        <div
+                          className="level-item level-left"
+                        >
+                          <Breadcrumb>
+                            <nav
+                              aria-label="breadcrumbs"
+                              className="breadcrumb"
+                            >
+                              <ul>
+                                <li
+                                  className="is-active"
                                 >
-                                  Dashboard
-                                </span>
-                              </li>
-                            </ul>
-                          </nav>
-                        </Breadcrumb>
+                                  <span
+                                    className=""
+                                  >
+                                    Dashboard
+                                  </span>
+                                </li>
+                              </ul>
+                            </nav>
+                          </Breadcrumb>
+                        </div>
                       </div>
-                    </div>
-                    <Connect(ClustersWidget)>
-                      <ClustersWidget
-                        clusters={Array []}
-                        dispatch={[Function]}
-                        offlineClusters={Array []}
-                        onlineClusters={Array []}
-                      >
-                        <div>
-                          <h5
-                            className="title is-5"
-                          >
-                            Clusters
-                          </h5>
-                          <MetricsWrapper>
-                            <div
-                              className="box"
+                      <Connect(ClustersWidget)>
+                        <ClustersWidget
+                          clusters={Array []}
+                          dispatch={[Function]}
+                          offlineClusters={Array []}
+                          onlineClusters={Array []}
+                        >
+                          <div>
+                            <h5
+                              className="title is-5"
                             >
+                              Clusters
+                            </h5>
+                            <MetricsWrapper>
                               <div
-                                className="level"
+                                className="box"
                               >
-                                <Indicator
-                                  label="Online Clusters"
+                                <div
+                                  className="level"
                                 >
-                                  <div
-                                    className="level-item"
+                                  <Indicator
+                                    label="Online Clusters"
                                   >
                                     <div
-                                      title="Online Clusters"
+                                      className="level-item"
                                     >
-                                      <p
-                                        className="heading"
+                                      <div
+                                        title="Online Clusters"
                                       >
-                                        Online Clusters
-                                      </p>
-                                      <p
-                                        className="title has-text-centered"
-                                      >
-                                        <span
-                                          className="tag is-success"
+                                        <p
+                                          className="heading"
+                                        >
+                                          Online Clusters
+                                        </p>
+                                        <p
+                                          className="title has-text-centered"
                                         >
-                                          0
-                                        </span>
-                                      </p>
+                                          <span
+                                            className="tag is-success"
+                                          >
+                                            0
+                                          </span>
+                                        </p>
+                                      </div>
                                     </div>
-                                  </div>
-                                </Indicator>
-                                <Indicator
-                                  label="Offline Clusters"
-                                >
-                                  <div
-                                    className="level-item"
+                                  </Indicator>
+                                  <Indicator
+                                    label="Offline Clusters"
                                   >
                                     <div
-                                      title="Offline Clusters"
+                                      className="level-item"
                                     >
-                                      <p
-                                        className="heading"
+                                      <div
+                                        title="Offline Clusters"
                                       >
-                                        Offline Clusters
-                                      </p>
-                                      <p
-                                        className="title has-text-centered"
-                                      >
-                                        <span
-                                          className="tag is-danger"
+                                        <p
+                                          className="heading"
+                                        >
+                                          Offline Clusters
+                                        </p>
+                                        <p
+                                          className="title has-text-centered"
                                         >
-                                          0
-                                        </span>
-                                      </p>
+                                          <span
+                                            className="tag is-danger"
+                                          >
+                                            0
+                                          </span>
+                                        </p>
+                                      </div>
                                     </div>
-                                  </div>
-                                </Indicator>
-                                <Indicator
-                                  label="Hide online clusters"
-                                >
-                                  <div
-                                    className="level-item"
+                                  </Indicator>
+                                  <Indicator
+                                    label="Hide online clusters"
                                   >
                                     <div
-                                      title="Hide online clusters"
+                                      className="level-item"
                                     >
-                                      <p
-                                        className="heading"
-                                      >
-                                        Hide online clusters
-                                      </p>
-                                      <p
-                                        className="title has-text-centered"
+                                      <div
+                                        title="Hide online clusters"
                                       >
-                                        <input
-                                          checked={false}
-                                          className="switch is-rounded"
-                                          id="switchRoundedDefault"
-                                          name="switchRoundedDefault"
-                                          onChange={[Function]}
-                                          type="checkbox"
-                                        />
-                                        <label
-                                          htmlFor="switchRoundedDefault"
-                                        />
-                                      </p>
+                                        <p
+                                          className="heading"
+                                        >
+                                          Hide online clusters
+                                        </p>
+                                        <p
+                                          className="title has-text-centered"
+                                        >
+                                          <input
+                                            checked={false}
+                                            className="switch is-rounded"
+                                            id="switchRoundedDefault"
+                                            name="switchRoundedDefault"
+                                            onChange={[Function]}
+                                            type="checkbox"
+                                          />
+                                          <label
+                                            htmlFor="switchRoundedDefault"
+                                          />
+                                        </p>
+                                      </div>
                                     </div>
-                                  </div>
-                                </Indicator>
+                                  </Indicator>
+                                </div>
                               </div>
-                            </div>
-                          </MetricsWrapper>
-                        </div>
-                      </ClustersWidget>
-                    </Connect(ClustersWidget)>
-                  </div>
-                </Dashboard>
-              </Route>
-            </Switch>
-          </main>
-          <div
-            className="Layout__alerts"
-          />
-        </div>
+                            </MetricsWrapper>
+                          </div>
+                        </ClustersWidget>
+                      </Connect(ClustersWidget)>
+                    </div>
+                  </Dashboard>
+                </Route>
+              </Switch>
+            </main>
+            <div
+              className="Layout__alerts"
+            />
+          </div>
+        </Component>
       </App>
     </Router>
   </StaticRouter>

+ 11 - 50
kafka-ui-react-app/src/components/common/Button/Button.tsx

@@ -1,44 +1,5 @@
 import styled from 'styled-components';
 
-const buttonStyles = {
-  primary: {
-    backgroundColor: {
-      normal: '#4F4FFF',
-      hover: '#1717CF',
-      active: '#1414B8',
-    },
-    color: '#FFFFFF',
-    invertedColors: {
-      normal: '#4F4FFF',
-      hover: '#1717CF',
-      active: '#1414B8',
-    },
-  },
-  secondary: {
-    backgroundColor: {
-      normal: '#F1F2F3',
-      hover: '#E3E6E8',
-      active: '#D5DADD',
-    },
-    color: '#171A1C',
-    invertedColors: {
-      normal: '#73848C',
-      hover: '#454F54',
-      active: '#171A1C',
-    },
-  },
-  height: {
-    S: '24px',
-    M: '32px',
-    L: '40px',
-  },
-  fontSize: {
-    S: '14px',
-    M: '14px',
-    L: '16px',
-  },
-};
-
 interface Props {
   buttonType: 'primary' | 'secondary';
   buttonSize: 'S' | 'M' | 'L';
@@ -60,34 +21,34 @@ const Button = styled('button')<Props>`
   background: ${(props) =>
     props.isInverted
       ? 'transparent'
-      : buttonStyles[props.buttonType].backgroundColor.normal};
+      : props.theme.buttonStyles[props.buttonType].backgroundColor.normal};
   color: ${(props) =>
     props.isInverted
-      ? buttonStyles[props.buttonType].invertedColors.normal
-      : buttonStyles[props.buttonType].color};
-  font-size: ${(props) => buttonStyles.fontSize[props.buttonSize]};
-  height: ${(props) => buttonStyles.height[props.buttonSize]};
+      ? props.theme.buttonStyles[props.buttonType].invertedColors.normal
+      : props.theme.buttonStyles[props.buttonType].color};
+  font-size: ${(props) => props.theme.buttonStyles.fontSize[props.buttonSize]};
+  height: ${(props) => props.theme.buttonStyles.height[props.buttonSize]};
 
   &:hover:enabled {
     background: ${(props) =>
       props.isInverted
         ? 'transparent'
-        : buttonStyles[props.buttonType].backgroundColor.hover};
+        : props.theme.buttonStyles[props.buttonType].backgroundColor.hover};
     color: ${(props) =>
       props.isInverted
-        ? buttonStyles[props.buttonType].invertedColors.hover
-        : buttonStyles[props.buttonType].color};
+        ? props.theme.buttonStyles[props.buttonType].invertedColors.hover
+        : props.theme.buttonStyles[props.buttonType].color};
     cursor: pointer;
   }
   &:active:enabled {
     background: ${(props) =>
       props.isInverted
         ? 'transparent'
-        : buttonStyles[props.buttonType].backgroundColor.active};
+        : props.theme.buttonStyles[props.buttonType].backgroundColor.active};
     color: ${(props) =>
       props.isInverted
-        ? buttonStyles[props.buttonType].invertedColors.active
-        : buttonStyles[props.buttonType].color};
+        ? props.theme.buttonStyles[props.buttonType].invertedColors.active
+        : props.theme.buttonStyles[props.buttonType].color};
   }
   &:disabled {
     opacity: 0.5;

+ 78 - 0
kafka-ui-react-app/src/theme/theme.ts

@@ -0,0 +1,78 @@
+export const Colors = {
+  neutral: {
+    '0': '#FFFFFF',
+    '5': '#F1F2F3',
+    '10': '#E3E6E8',
+    '15': '#D5DADD',
+    '20': '#C7CED1',
+    '30': '#ABB5BA',
+    '40': '#8F9CA3',
+    '50': '#73848C',
+    '60': '#5C6970',
+    '70': '#454F54',
+    '80': '#2F3639',
+    '90': '#171A1C',
+  },
+  green: {
+    '10': '#D6F5E0',
+    '15': '#C2F0D1',
+    '30': '#85E0A3',
+    '40': '#5CD685',
+    '60': '#29A352',
+  },
+  brand: {
+    '20': '#A3A3F5',
+    '50': '#4F4FFF',
+    '55': '#1717CF',
+    '60': '#1414B8',
+  },
+  red: {
+    '50': '#E51A1A',
+  },
+  orange: {
+    '10': '#FFEECC',
+  },
+};
+
+const theme = {
+  buttonStyles: {
+    primary: {
+      backgroundColor: {
+        normal: Colors.brand[50],
+        hover: Colors.brand[55],
+        active: Colors.brand[60],
+      },
+      color: Colors.neutral[0],
+      invertedColors: {
+        normal: Colors.brand[50],
+        hover: Colors.brand[55],
+        active: Colors.brand[60],
+      },
+    },
+    secondary: {
+      backgroundColor: {
+        normal: Colors.neutral[5],
+        hover: Colors.neutral[10],
+        active: Colors.neutral[15],
+      },
+      color: Colors.neutral[90],
+      invertedColors: {
+        normal: Colors.neutral[50],
+        hover: Colors.neutral[70],
+        active: Colors.neutral[90],
+      },
+    },
+    height: {
+      S: '24px',
+      M: '32px',
+      L: '40px',
+    },
+    fontSize: {
+      S: '14px',
+      M: '14px',
+      L: '16px',
+    },
+  },
+};
+
+export default theme;