Repository: isucon/isucon11-qualify (language: go)

Issue:
[frontend]ヘッダーの作成



Discussion / hints:

Fix patch:
diff --git a/webapp/frontend/package-lock.json b/webapp/frontend/package-lock.json
index 9bca9597a..81e30ab5f 100644
--- a/webapp/frontend/package-lock.json
+++ b/webapp/frontend/package-lock.json
@@ -310,6 +310,44 @@
         }
       }
     },
+    "@fullhuman/postcss-purgecss": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz",
+      "integrity": "sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==",
+      "dev": true,
+      "requires": {
+        "postcss": "7.0.32",
+        "purgecss": "^2.3.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.32",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
+          "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -348,6 +386,12 @@
       "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
       "dev": true
     },
+    "@types/node": {
+      "version": "15.12.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
+      "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==",
+      "dev": true
+    },
     "@types/prop-types": {
       "version": "15.7.3",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
@@ -374,6 +418,15 @@
         "@types/react": "*"
       }
     },
+    "@types/react-modal": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.12.0.tgz",
+      "integrity": "sha512-UnHu/YO73NZLwqFpju/c0tqiswR0UHIfeO16rkfLVJUIMfQsl7X0CBm99H5XXgBMe/PgtQ/Rkud72iuRBr1TeA==",
+      "dev": true,
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/react-router": {
       "version": "5.1.15",
       "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
@@ -567,6 +620,23 @@
       "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
       "dev": true
     },
+    "acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "dev": true
+    },
     "ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -646,6 +716,49 @@
       "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
       "dev": true
     },
+    "autoprefixer": {
+      "version": "9.8.6",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
+      "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^4.12.0",
+        "caniuse-lite": "^1.0.30001109",
+        "colorette": "^1.2.1",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "postcss": "^7.0.32",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.36",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
+          "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -684,6 +797,12 @@
         "node-releases": "^1.1.71"
       }
     },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+      "dev": true
+    },
     "call-bind": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -700,6 +819,12 @@
       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true
     },
+    "camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "dev": true
+    },
     "caniuse-lite": {
       "version": "1.0.30001236",
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz",
@@ -717,6 +842,16 @@
         "supports-color": "^5.3.0"
       }
     },
+    "color": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
+      "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.1",
+        "color-string": "^1.5.4"
+      }
+    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -732,12 +867,28 @@
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "dev": true
     },
+    "color-string": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz",
+      "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==",
+      "dev": true,
+      "requires": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
     "colorette": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
       "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
       "dev": true
     },
+    "commander": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+      "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+      "dev": true
+    },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -764,6 +915,18 @@
         "which": "^2.0.1"
       }
     },
+    "css-unit-converter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+      "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
+      "dev": true
+    },
+    "cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true
+    },
     "csstype": {
       "version": "3.0.8",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
@@ -794,6 +957,23 @@
         "object-keys": "^1.0.12"
       }
     },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+      "dev": true
+    },
+    "detective": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
+      "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
+      "dev": true,
+      "requires": {
+        "acorn-node": "^1.6.1",
+        "defined": "^1.0.0",
+        "minimist": "^1.1.1"
+      }
+    },
     "dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -1174,6 +1354,11 @@
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
+    "exenv": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
+      "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
+    },
     "fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -1233,6 +1418,16 @@
         "to-regex-range": "^5.0.1"
       }
     },
+    "find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
     "flat-cache": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -1249,6 +1444,17 @@
       "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
       "dev": true
     },
+    "fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      }
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -1342,6 +1548,12 @@
         }
       }
     },
+    "graceful-fs": {
+      "version": "4.2.6",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
+      "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
+      "dev": true
+    },
     "has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -1390,6 +1602,12 @@
         "react-is": "^16.7.0"
       }
     },
+    "html-tags": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
+      "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+      "dev": true
+    },
     "ignore": {
       "version": "4.0.6",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -1439,6 +1657,12 @@
         "side-channel": "^1.0.4"
       }
     },
+    "is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+      "dev": true
+    },
     "is-bigint": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz",
@@ -1598,6 +1822,15 @@
         "minimist": "^1.2.5"
       }
     },
+    "jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
     "jsx-ast-utils": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
@@ -1618,6 +1851,15 @@
         "type-check": "~0.4.0"
       }
     },
+    "locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^5.0.0"
+      }
+    },
     "lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -1636,6 +1878,12 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "lodash.toarray": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+      "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=",
+      "dev": true
+    },
     "lodash.truncate": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -1726,17 +1974,50 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "dev": true
     },
+    "node-emoji": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
+      "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
+      "dev": true,
+      "requires": {
+        "lodash.toarray": "^4.4.0"
+      }
+    },
     "node-releases": {
       "version": "1.1.73",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
       "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==",
       "dev": true
     },
+    "normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "dev": true
+    },
+    "normalize.css": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
+      "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==",
+      "dev": true
+    },
+    "num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+      "dev": true
+    },
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
+    "object-hash": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+      "dev": true
+    },
     "object-inspect": {
       "version": "1.10.3",
       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
@@ -1818,6 +2099,24 @@
         "word-wrap": "^1.2.3"
       }
     },
+    "p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "requires": {
+        "yocto-queue": "^0.1.0"
+      }
+    },
+    "p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^3.0.2"
+      }
+    },
     "parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -1827,6 +2126,12 @@
         "callsites": "^3.0.0"
       }
     },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
+    },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -1876,6 +2181,135 @@
         "source-map-js": "^0.6.2"
       }
     },
+    "postcss-functions": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz",
+      "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.2",
+        "object-assign": "^4.1.1",
+        "postcss": "^6.0.9",
+        "postcss-value-parser": "^3.3.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "6.0.23",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.1",
+            "source-map": "^0.6.1",
+            "supports-color": "^5.4.0"
+          }
+        },
+        "postcss-value-parser": {
+          "version": "3.3.1",
+          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-js": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz",
+      "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==",
+      "dev": true,
+      "requires": {
+        "camelcase-css": "^2.0.1",
+        "postcss": "^7.0.18"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.36",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
+          "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-nested": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz",
+      "integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.32",
+        "postcss-selector-parser": "^6.0.2"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.36",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
+          "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-selector-parser": {
+      "version": "6.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
+      "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
+      "dev": true,
+      "requires": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      }
+    },
+    "postcss-value-parser": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+      "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+      "dev": true
+    },
     "prelude-ls": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -1888,6 +2322,23 @@
       "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==",
       "dev": true
     },
+    "prettier-plugin-tailwind": {
+      "version": "2.2.10",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwind/-/prettier-plugin-tailwind-2.2.10.tgz",
+      "integrity": "sha512-QTzSygDG822zqyGmhJFcRXvz/Dx9LYsWETEbPu11XcpT9KoeNSDAPa+12YfPXd9O7j4oCX/keZFnWi2gTOlhQw==",
+      "dev": true,
+      "requires": {
+        "prettier": "^2.1.2",
+        "tailwind-classes-sorter": "^0.2.5",
+        "tailwindcss": "^1.8.13"
+      }
+    },
+    "pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
+      "dev": true
+    },
     "progress": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -1910,6 +2361,46 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
+    "purgecss": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.3.0.tgz",
+      "integrity": "sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==",
+      "dev": true,
+      "requires": {
+        "commander": "^5.0.0",
+        "glob": "^7.0.0",
+        "postcss": "7.0.32",
+        "postcss-selector-parser": "^6.0.2"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.32",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
+          "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
     "queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -1935,11 +2426,32 @@
         "scheduler": "^0.20.2"
       }
     },
+    "react-icons": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.2.0.tgz",
+      "integrity": "sha512-rmzEDFt+AVXRzD7zDE21gcxyBizD/3NqjbX6cmViAgdqfJ2UiLer8927/QhhrXQV7dEj/1EGuOTPp7JnLYVJKQ=="
+    },
     "react-is": {
       "version": "16.13.1",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
     },
+    "react-lifecycles-compat": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+      "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+    },
+    "react-modal": {
+      "version": "3.14.3",
+      "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.14.3.tgz",
+      "integrity": "sha512-+C2KODVKyu20zHXPJxfOOcf571L1u/EpFlH+oS/3YDn8rgVE51QZuxuuIwabJ8ZFnOEHaD+r6XNjqwtxZnXO0g==",
+      "requires": {
+        "exenv": "^1.2.0",
+        "prop-types": "^15.7.2",
+        "react-lifecycles-compat": "^3.0.0",
+        "warning": "^4.0.3"
+      }
+    },
     "react-refresh": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz",
@@ -1977,6 +2489,24 @@
         "tiny-warning": "^1.0.0"
       }
     },
+    "reduce-css-calc": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+      "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+      "dev": true,
+      "requires": {
+        "css-unit-converter": "^1.1.1",
+        "postcss-value-parser": "^3.3.0"
+      },
+      "dependencies": {
+        "postcss-value-parser": {
+          "version": "3.3.1",
+          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+          "dev": true
+        }
+      }
+    },
     "regenerator-runtime": {
       "version": "0.13.7",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
@@ -2105,6 +2635,15 @@
         "object-inspect": "^1.9.0"
       }
     },
+    "simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
     "slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -2277,6 +2816,176 @@
         }
       }
     },
+    "tailwind-classes-sorter": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/tailwind-classes-sorter/-/tailwind-classes-sorter-0.2.5.tgz",
+      "integrity": "sha512-7S0AaDitt+Fjy9m3v0GrQ/KZrCswNDD25SSXX9U/HIB5h9lk0ImSkq/VVcnzu78cRQxR0fFfvHYFdfcqN3dCGA==",
+      "dev": true,
+      "requires": {
+        "find-up": "^5.0.0"
+      }
+    },
+    "tailwindcss": {
+      "version": "1.9.6",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz",
+      "integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==",
+      "dev": true,
+      "requires": {
+        "@fullhuman/postcss-purgecss": "^2.1.2",
+        "autoprefixer": "^9.4.5",
+        "browserslist": "^4.12.0",
+        "bytes": "^3.0.0",
+        "chalk": "^3.0.0 || ^4.0.0",
+        "color": "^3.1.2",
+        "detective": "^5.2.0",
+        "fs-extra": "^8.0.0",
+        "html-tags": "^3.1.0",
+        "lodash": "^4.17.20",
+        "node-emoji": "^1.8.1",
+        "normalize.css": "^8.0.1",
+        "object-hash": "^2.0.3",
+        "postcss": "^7.0.11",
+        "postcss-functions": "^3.0.0",
+        "postcss-js": "^2.0.0",
+        "postcss-nested": "^4.1.1",
+        "postcss-selector-parser": "^6.0.0",
+        "postcss-value-parser": "^4.1.0",
+        "pretty-hrtime": "^1.0.3",
+        "reduce-css-calc": "^2.1.6",
+        "resolve": "^1.14.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.36",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
+          "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          },
+          "dependencies": {
+            "ansi-styles": {
+              "version": "3.2.1",
+              "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+              "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+              "dev": true,
+              "requires": {
+                "color-convert": "^1.9.0"
+              }
+            },
+            "chalk": {
+              "version": "2.4.2",
+              "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+              "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+              "dev": true,
+              "requires": {
+                "ansi-styles": "^3.2.1",
+                "escape-string-regexp": "^1.0.5",
+                "supports-color": "^5.3.0"
+              },
+              "dependencies": {
+                "supports-color": {
+                  "version": "5.5.0",
+                  "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+                  "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+                  "dev": true,
+                  "requires": {
+                    "has-flag": "^3.0.0"
+                  }
+                }
+              }
+            },
+            "color-convert": {
+              "version": "1.9.3",
+              "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+              "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+              "dev": true,
+              "requires": {
+                "color-name": "1.1.3"
+              }
+            },
+            "color-name": {
+              "version": "1.1.3",
+              "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+              "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+              "dev": true
+            },
+            "has-flag": {
+              "version": "3.0.0",
+              "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+              "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+              "dev": true
+            },
+            "supports-color": {
+              "version": "6.1.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+              "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+              "dev": true,
+              "requires": {
+                "has-flag": "^3.0.0"
+              }
+            }
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -2356,6 +3065,12 @@
         "which-boxed-primitive": "^1.0.2"
       }
     },
+    "universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true
+    },
     "uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2365,6 +3080,12 @@
         "punycode": "^2.1.0"
       }
     },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
     "v8-compile-cache": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
@@ -2461,6 +3182,14 @@
         }
       }
     },
+    "warning": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+      "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+      "requires": {
+        "loose-envify": "^1.0.0"
+      }
+    },
     "which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2501,11 +3230,23 @@
       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
       "dev": true
     },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true
+    },
     "yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
     }
   }
 }
diff --git a/webapp/frontend/package.json b/webapp/frontend/package.json
index 9dbc0fc8f..9545c4af5 100644
--- a/webapp/frontend/package.json
+++ b/webapp/frontend/package.json
@@ -11,11 +11,15 @@
   "dependencies": {
     "react": "^17.0.0",
     "react-dom": "^17.0.0",
+    "react-icons": "^4.2.0",
+    "react-modal": "^3.14.3",
     "react-router-dom": "^5.2.0"
   },
   "devDependencies": {
+    "@types/node": "^15.12.2",
     "@types/react": "^17.0.0",
     "@types/react-dom": "^17.0.0",
+    "@types/react-modal": "^3.12.0",
     "@types/react-router-dom": "^5.1.7",
     "@typescript-eslint/eslint-plugin": "^4.26.1",
     "@typescript-eslint/parser": "^4.26.1",
@@ -25,6 +29,7 @@
     "eslint-plugin-react": "^7.24.0",
     "eslint-plugin-react-hooks": "^4.2.0",
     "prettier": "^2.3.1",
+    "prettier-plugin-tailwind": "^2.2.10",
     "typescript": "^4.3.2",
     "vite": "^2.3.7",
     "vite-plugin-windicss": "^1.0.3"
diff --git a/webapp/frontend/src/App.css b/webapp/frontend/src/App.css
deleted file mode 100644
index 8da3fde63..000000000
--- a/webapp/frontend/src/App.css
+++ /dev/null
@@ -1,42 +0,0 @@
-.App {
-  text-align: center;
-}
-
-.App-logo {
-  height: 40vmin;
-  pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
-  .App-logo {
-    animation: App-logo-spin infinite 20s linear;
-  }
-}
-
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #61dafb;
-}
-
-@keyframes App-logo-spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
-}
-
-button {
-  font-size: calc(10px + 2vmin);
-}
diff --git a/webapp/frontend/src/App.tsx b/webapp/frontend/src/App.tsx
index eef12010f..4f2473ef5 100644
--- a/webapp/frontend/src/App.tsx
+++ b/webapp/frontend/src/App.tsx
@@ -1,43 +1,26 @@
-import { useState } from 'react'
-import logo from './logo.svg'
-import './App.css'
+import { BrowserRouter, Switch, Route } from 'react-router-dom'
+import PageHeader from './components/PageHeader/PageHeader'
+import Auth from './pages/Auth'
+import GuardedRoute from './router/GuardedRoute'
 
 const App = () => {
-  const [count, setCount] = useState(0)
-
   return (
-    <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>Hello Vite + React!</p>
-        <p>
-          <button type="button" onClick={() => setCount(count => count + 1)}>
-            count is: {count}
-          </button>
-        </p>
-        <p>
-          Edit <code>App.tsx</code> and save to test HMR updates.
-        </p>
-        <p>
-          <a
-            className="App-link"
-            href="https://reactjs.org"
-            target="_blank"
-            rel="noopener noreferrer"
-          >
-            Learn React
-          </a>
-          {' | '}
-          <a
-            className="App-link"
-            href="https://vitejs.dev/guide/features.html"
-            target="_blank"
-            rel="noopener noreferrer"
-          >
-            Vite Docs
-          </a>
-        </p>
-      </header>
+    <div className="text-primary-700">
+      <BrowserRouter>
+        <PageHeader></PageHeader>
+        <Switch>
+          <GuardedRoute path="/" exact></GuardedRoute>
+          <GuardedRoute path="/isu/condition" exact>
+            <div>通知画面</div>
+          </GuardedRoute>
+          <GuardedRoute path="/isu/search" exact>
+            <div>検索画面</div>
+          </GuardedRoute>
+          <Route path="/login">
+            <Auth />
+          </Route>
+        </Switch>
+      </BrowserRouter>
     </div>
   )
 }
diff --git a/webapp/frontend/src/assets/logo.png b/webapp/frontend/src/assets/logo.png
new file mode 100644
index 000000000..07f946749
Binary files /dev/null and b/webapp/frontend/src/assets/logo.png differ
diff --git a/webapp/frontend/src/components/PageHeader/ControlItem.tsx b/webapp/frontend/src/components/PageHeader/ControlItem.tsx
new file mode 100644
index 000000000..c6f6b41c8
--- /dev/null
+++ b/webapp/frontend/src/components/PageHeader/ControlItem.tsx
@@ -0,0 +1,5 @@
+const ControlItem = ({ children }: { children: JSX.Element }) => {
+  return <div className="mr-4">{children}</div>
+}
+
+export default ControlItem
diff --git a/webapp/frontend/src/components/PageHeader/ControlLinkItem.tsx b/webapp/frontend/src/components/PageHeader/ControlLinkItem.tsx
new file mode 100644
index 000000000..f991726ba
--- /dev/null
+++ b/webapp/frontend/src/components/PageHeader/ControlLinkItem.tsx
@@ -0,0 +1,21 @@
+import { Link } from 'react-router-dom'
+import ControlItem from './ControlItem'
+
+interface Props {
+  to: string
+  label: string
+  icon: JSX.Element
+}
+
+const ControlLinkItem = (props: Props) => {
+  return (
+    <ControlItem>
+      <Link to={props.to} className="flex items-center mr-1 text-primary-700">
+        {props.icon}
+        <div className="ml-1">{props.label}</div>
+      </Link>
+    </ControlItem>
+  )
+}
+
+export default ControlLinkItem
diff --git a/webapp/frontend/src/components/PageHeader/Controls.tsx b/webapp/frontend/src/components/PageHeader/Controls.tsx
new file mode 100644
index 000000000..289c1ba47
--- /dev/null
+++ b/webapp/frontend/src/components/PageHeader/Controls.tsx
@@ -0,0 +1,43 @@
+import { useStateContext } from '../../context/state'
+import { MdAccountCircle } from 'react-icons/md'
+import { useState } from 'react'
+
+import ControlItem from './ControlItem'
+import UserControlModal from './UserControlModal'
+import ControlLinkItem from './ControlLinkItem'
+import { IoIosNotifications, IoMdSearch } from 'react-icons/io'
+
+const Controls = () => {
+  const [isOpenModal, setIsOpenModal] = useState(false)
+  const toggleModal = () => {
+    setIsOpenModal(!isOpenModal)
+  }
+  const me = useStateContext().me
+  if (!me) {
+    return <></>
+  }
+
+  return (
+    <div className="flex items-center ml-auto">
+      <ControlLinkItem
+        to="/isu/condition"
+        label="ISUの状態"
+        icon={<IoIosNotifications />}
+      />
+      <ControlLinkItem
+        to="/isu/search"
+        label="ISUの検索"
+        icon={<IoMdSearch />}
+      />
+      <ControlItem>
+        <div className="flex items-center cursor-pointer" onClick={toggleModal}>
+          <MdAccountCircle />
+          <div className="ml-1">{me.jiaUserID}</div>
+        </div>
+      </ControlItem>
+      <UserControlModal isOpen={isOpenModal} toggle={toggleModal} />
+    </div>
+  )
+}
+
+export default Controls
diff --git a/webapp/frontend/src/components/PageHeader/PageHeader.tsx b/webapp/frontend/src/components/PageHeader/PageHeader.tsx
new file mode 100644
index 000000000..8cfdbecb1
--- /dev/null
+++ b/webapp/frontend/src/components/PageHeader/PageHeader.tsx
@@ -0,0 +1,16 @@
+import { Link } from 'react-router-dom'
+import Controls from './Controls'
+import logo from '/@/assets/logo.png'
+
+const PageHeader = () => {
+  return (
+    <header className="h-14 flex items-center p-2 bg-primary-400">
+      <Link to="/">
+        <img src={logo} alt="isucondition" className="cursor-pointer" />
+      </Link>
+      <Controls />
+    </header>
+  )
+}
+
+export default PageHeader
diff --git a/webapp/frontend/src/components/PageHeader/UserControlModal.tsx b/webapp/frontend/src/components/PageHeader/UserControlModal.tsx
new file mode 100644
index 000000000..fafcc305c
--- /dev/null
+++ b/webapp/frontend/src/components/PageHeader/UserControlModal.tsx
@@ -0,0 +1,37 @@
+import Modal from 'react-modal'
+import { IoMdLogOut } from 'react-icons/io'
+import { Link } from 'react-router-dom'
+import { useDispatchContext } from '../../context/state'
+
+interface Props {
+  isOpen: boolean
+  toggle: () => void
+}
+
+const UserControlModal = (props: Props) => {
+  const dispatch = useDispatchContext()
+  const logout = () => {
+    dispatch({ type: 'logout' })
+  }
+
+  return (
+    <Modal
+      isOpen={props.isOpen}
+      onRequestClose={props.toggle}
+      className="right-8 top-8 border-dark-200 bg-gray-50 absolute p-4 w-40 border rounded"
+      overlayClassName="fixed inset-0"
+      shouldCloseOnOverlayClick={true}
+    >
+      <Link
+        to="/"
+        onClick={logout}
+        className="flex items-center text-primary-800"
+      >
+        <IoMdLogOut className="mr-3" size={20} />
+        <div>logout</div>
+      </Link>
+    </Modal>
+  )
+}
+
+export default UserControlModal
diff --git a/webapp/frontend/src/context/state.tsx b/webapp/frontend/src/context/state.tsx
new file mode 100644
index 000000000..f75f4fae0
--- /dev/null
+++ b/webapp/frontend/src/context/state.tsx
@@ -0,0 +1,62 @@
+import { createContext, Dispatch, useContext, useReducer } from 'react'
+
+interface User {
+  jiaUserID: string
+}
+interface State {
+  me: User | null
+}
+type Action = { type: 'login'; user: User } | { type: 'logout' }
+
+const initialState: State = {
+  me: null
+}
+
+const stateContext = createContext<State>(initialState)
+const dispatchContext = createContext<Dispatch<Action> | null>(null)
+
+const stateReducer = (state: State, action: Action): State => {
+  switch (action.type) {
+    case 'login': {
+      return { ...state, me: action.user }
+    }
+    case 'logout': {
+      return { ...state, me: null }
+    }
+    default: {
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
+      const _exhaustiveCheck: never = action
+      throw new Error('invalid action')
+    }
+  }
+}
+
+const StateContextProvider = ({ children }: { children: JSX.Element }) => {
+  const [state, dispatch] = useReducer(stateReducer, initialState)
+
+  return (
+    <stateContext.Provider value={state}>
+      <dispatchContext.Provider value={dispatch}>
+        {children}
+      </dispatchContext.Provider>
+    </stateContext.Provider>
+  )
+}
+
+export const useStateContext = () => {
+  const state = useContext(stateContext)
+  if (!state) {
+    throw new Error('require wrapped by stateContext')
+  }
+  return state
+}
+
+export const useDispatchContext = () => {
+  const dispatch = useContext(dispatchContext)
+  if (!dispatch) {
+    throw new Error('require wrapped by stateContext')
+  }
+  return dispatch
+}
+
+export default StateContextProvider
diff --git a/webapp/frontend/src/index.css b/webapp/frontend/src/index.css
index ec2585e8c..a11878610 100644
--- a/webapp/frontend/src/index.css
+++ b/webapp/frontend/src/index.css
@@ -11,3 +11,7 @@ code {
   font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
     monospace;
 }
+
+a {
+  text-decoration: none;
+}
diff --git a/webapp/frontend/src/main.tsx b/webapp/frontend/src/main.tsx
index 1787a946e..6d83b85a4 100644
--- a/webapp/frontend/src/main.tsx
+++ b/webapp/frontend/src/main.tsx
@@ -3,22 +3,16 @@ import ReactDOM from 'react-dom'
 import './index.css'
 import 'windi.css'
 import App from './App'
-import { BrowserRouter, Route, Switch } from 'react-router-dom'
-import GuardedRoute from './router/GuardedRoute'
-import Auth from './pages/Auth'
+import StateContextProvider from './context/state'
+import Modal from 'react-modal'
 
 ReactDOM.render(
   <StrictMode>
-    <BrowserRouter>
-      <Switch>
-        <GuardedRoute path="/" exact>
-          <App />
-        </GuardedRoute>
-        <Route path="/login">
-          <Auth />
-        </Route>
-      </Switch>
-    </BrowserRouter>
+    <StateContextProvider>
+      <App />
+    </StateContextProvider>
   </StrictMode>,
   document.getElementById('root')
 )
+
+Modal.setAppElement('#root')
diff --git a/webapp/frontend/src/router/GuardedRoute.tsx b/webapp/frontend/src/router/GuardedRoute.tsx
index ac014604d..87f29dea1 100644
--- a/webapp/frontend/src/router/GuardedRoute.tsx
+++ b/webapp/frontend/src/router/GuardedRoute.tsx
@@ -1,11 +1,11 @@
 import { Route, Redirect } from 'react-router-dom'
+import { useStateContext } from '../context/state'
 
 const GuardedRoute = <T extends { path: string; children?: JSX.Element }>(
   props: T
 ) => {
-  // TODO: ここで GET /user/me をたたく or storeに問い合わせ
-  const me = null
-  if (!me) {
+  const state = useStateContext()
+  if (!state.me) {
     return <Redirect to="/login" />
   }
 
diff --git a/webapp/frontend/tailwind.config.js b/webapp/frontend/tailwind.config.js
new file mode 100644
index 000000000..2d48de5aa
--- /dev/null
+++ b/webapp/frontend/tailwind.config.js
@@ -0,0 +1,15 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const colors = require('windicss/colors')
+
+module.exports = {
+  theme: {
+    backgroundColor: theme => ({
+      ...theme('colors'),
+      primary: colors.indigo
+    }),
+    textColor: theme => ({
+      ...theme('colors'),
+      primary: colors.gray
+    })
+  }
+}
diff --git a/webapp/frontend/tsconfig.json b/webapp/frontend/tsconfig.json
index a3f3e1129..e99fc002a 100644
--- a/webapp/frontend/tsconfig.json
+++ b/webapp/frontend/tsconfig.json
@@ -15,5 +15,8 @@
     "noEmit": true,
     "jsx": "react-jsx"
   },
+  "paths": {
+    "/@/*": ["src/*"]
+  },
   "include": ["./src"]
 }
diff --git a/webapp/frontend/vite.config.ts b/webapp/frontend/vite.config.ts
index 208bdd761..41ac4e353 100644
--- a/webapp/frontend/vite.config.ts
+++ b/webapp/frontend/vite.config.ts
@@ -1,9 +1,17 @@
 import { defineConfig } from 'vite'
 import reactRefresh from '@vitejs/plugin-react-refresh'
 import WindiCSS from 'vite-plugin-windicss'
+import path from 'path'
+
+const srcPath = path.resolve(__dirname, 'src').replace(/\\/g, '/')
 
 // https://vitejs.dev/config/
 export default defineConfig({
+  resolve: {
+    alias: {
+      '/@': srcPath
+    }
+  },
   plugins: [reactRefresh(), WindiCSS()],
   esbuild: {
     jsxInject: `import React from 'react'`


Test patch: