Implement notify new version in WebUI, also configure CORS for the proxy endpoint /version
- commit
- efb1aec55daa81f58a250f278fd26cf877a9c2ea
- author
- bnema · · 2023-11-05 09:30 UTC
- parent
- 2589b4c
- signature
- unsigned
8 files · +77 -57
M go.mod +0 -3
| @@ -18,7 +18,6 @@ require ( | |||
| 18 | 18 | ) | |
| 19 | 19 | ||
| 20 | 20 | require ( | |
| 21 | - | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect | |
| 22 | 21 | github.com/dustin/go-humanize v1.0.1 // indirect | |
| 23 | 22 | github.com/inconshreveable/mousetrap v1.1.0 // indirect | |
| 24 | 23 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | |
| @@ -28,7 +27,6 @@ require ( | |||
| 28 | 27 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | |
| 29 | 28 | github.com/rivo/uniseg v0.4.4 // indirect | |
| 30 | 29 | github.com/spf13/pflag v1.0.5 // indirect | |
| 31 | - | github.com/stretchr/testify v1.8.4 // indirect | |
| 32 | 30 | lukechampine.com/uint128 v1.3.0 // indirect | |
| 33 | 31 | modernc.org/cc/v3 v3.41.0 // indirect | |
| 34 | 32 | modernc.org/ccgo/v3 v3.16.15 // indirect | |
| @@ -52,7 +50,6 @@ require ( | |||
| 52 | 50 | github.com/gorilla/context v1.1.1 // indirect | |
| 53 | 51 | github.com/gorilla/css v1.0.0 // indirect | |
| 54 | 52 | github.com/gorilla/securecookie v1.1.1 // indirect | |
| 55 | - | github.com/labstack/echo v3.3.10+incompatible | |
| 56 | 53 | github.com/labstack/gommon v0.4.0 // indirect | |
| 57 | 54 | github.com/mattn/go-colorable v0.1.13 // indirect | |
| 58 | 55 | github.com/mattn/go-isatty v0.0.20 // indirect | |
| @@ -18,7 +18,6 @@ require ( | |||||
| 18 | ) | 18 | ) | ||
| 19 | 19 | ||||
| 20 | require ( | 20 | require ( | ||
| 21 | - | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect | |||
| 22 | github.com/dustin/go-humanize v1.0.1 // indirect | 21 | github.com/dustin/go-humanize v1.0.1 // indirect | ||
| 23 | github.com/inconshreveable/mousetrap v1.1.0 // indirect | 22 | github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||
| 24 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | 23 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | ||
| @@ -28,7 +27,6 @@ require ( | |||||
| 28 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | 27 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||
| 29 | github.com/rivo/uniseg v0.4.4 // indirect | 28 | github.com/rivo/uniseg v0.4.4 // indirect | ||
| 30 | github.com/spf13/pflag v1.0.5 // indirect | 29 | github.com/spf13/pflag v1.0.5 // indirect | ||
| 31 | - | github.com/stretchr/testify v1.8.4 // indirect | |||
| 32 | lukechampine.com/uint128 v1.3.0 // indirect | 30 | lukechampine.com/uint128 v1.3.0 // indirect | ||
| 33 | modernc.org/cc/v3 v3.41.0 // indirect | 31 | modernc.org/cc/v3 v3.41.0 // indirect | ||
| 34 | modernc.org/ccgo/v3 v3.16.15 // indirect | 32 | modernc.org/ccgo/v3 v3.16.15 // indirect | ||
| @@ -52,7 +50,6 @@ require ( | |||||
| 52 | github.com/gorilla/context v1.1.1 // indirect | 50 | github.com/gorilla/context v1.1.1 // indirect | ||
| 53 | github.com/gorilla/css v1.0.0 // indirect | 51 | github.com/gorilla/css v1.0.0 // indirect | ||
| 54 | github.com/gorilla/securecookie v1.1.1 // indirect | 52 | github.com/gorilla/securecookie v1.1.1 // indirect | ||
| 55 | - | github.com/labstack/echo v3.3.10+incompatible | |||
| 56 | github.com/labstack/gommon v0.4.0 // indirect | 53 | github.com/labstack/gommon v0.4.0 // indirect | ||
| 57 | github.com/mattn/go-colorable v0.1.13 // indirect | 54 | github.com/mattn/go-colorable v0.1.13 // indirect | ||
| 58 | github.com/mattn/go-isatty v0.0.20 // indirect | 55 | github.com/mattn/go-isatty v0.0.20 // indirect | ||
M go.sum +1 -12 generated file: collapsed
M internal/httpserve/middleware/secure.go +6 -2
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | package middleware | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "fmt" | |
| 4 | 5 | "log" | |
| 5 | 6 | "os" | |
| 6 | 7 | ||
| @@ -12,14 +13,17 @@ import ( | |||
| 12 | 13 | "github.com/labstack/echo/v4/middleware" | |
| 13 | 14 | ) | |
| 14 | 15 | ||
| 15 | - | func SecureRoutes() echo.MiddlewareFunc { | |
| 16 | + | func SecureRoutes(a *server.App) echo.MiddlewareFunc { | |
| 17 | + | proxyURL := a.Config.Build.ProxyURL // <-- https://gordon-proxy.bnema.dev | |
| 18 | + | urlCheckVersion := a.Config.Build.ProxyURL + "/version" | |
| 19 | + | fmt.Println("Proxy URL:", proxyURL) | |
| 16 | 20 | return middleware.SecureWithConfig(middleware.SecureConfig{ | |
| 17 | 21 | XSSProtection: "1; mode=block", | |
| 18 | 22 | ContentTypeNosniff: "nosniff", | |
| 19 | 23 | XFrameOptions: "SAMEORIGIN", | |
| 20 | 24 | HSTSMaxAge: 3600, | |
| 21 | 25 | HSTSExcludeSubdomains: false, | |
| 22 | - | ContentSecurityPolicy: "default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; script-src 'self' 'unsafe-inline'", | |
| 26 | + | ContentSecurityPolicy: "default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' " + proxyURL + " " + urlCheckVersion, | |
| 23 | 27 | }) | |
| 24 | 28 | } | |
| 25 | 29 | ||
| @@ -1,6 +1,7 @@ | |||||
| 1 | package middleware | 1 | package middleware | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "fmt" | |||
| 4 | "log" | 5 | "log" | ||
| 5 | "os" | 6 | "os" | ||
| 6 | 7 | ||||
| @@ -12,14 +13,17 @@ import ( | |||||
| 12 | "github.com/labstack/echo/v4/middleware" | 13 | "github.com/labstack/echo/v4/middleware" | ||
| 13 | ) | 14 | ) | ||
| 14 | 15 | ||||
| 15 | - | func SecureRoutes() echo.MiddlewareFunc { | 16 | + | func SecureRoutes(a *server.App) echo.MiddlewareFunc { |
| 17 | + | proxyURL := a.Config.Build.ProxyURL // <-- https://gordon-proxy.bnema.dev | |||
| 18 | + | urlCheckVersion := a.Config.Build.ProxyURL + "/version" | |||
| 19 | + | fmt.Println("Proxy URL:", proxyURL) | |||
| 16 | return middleware.SecureWithConfig(middleware.SecureConfig{ | 20 | return middleware.SecureWithConfig(middleware.SecureConfig{ | ||
| 17 | XSSProtection: "1; mode=block", | 21 | XSSProtection: "1; mode=block", | ||
| 18 | ContentTypeNosniff: "nosniff", | 22 | ContentTypeNosniff: "nosniff", | ||
| 19 | XFrameOptions: "SAMEORIGIN", | 23 | XFrameOptions: "SAMEORIGIN", | ||
| 20 | HSTSMaxAge: 3600, | 24 | HSTSMaxAge: 3600, | ||
| 21 | HSTSExcludeSubdomains: false, | 25 | HSTSExcludeSubdomains: false, | ||
| 22 | - | ContentSecurityPolicy: "default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; script-src 'self' 'unsafe-inline'", | 26 | + | ContentSecurityPolicy: "default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' " + proxyURL + " " + urlCheckVersion, |
| 23 | }) | 27 | }) | ||
| 24 | } | 28 | } | ||
| 25 | 29 | ||||
M internal/httpserve/router.go +1 -1
| @@ -30,7 +30,7 @@ func RegisterRoutes(e *echo.Echo, a *server.App) *echo.Echo { | |||
| 30 | 30 | e.Use(middleware.ErrorHandler) | |
| 31 | 31 | ||
| 32 | 32 | // Use middlewares | |
| 33 | - | e.Use(middleware.SecureRoutes()) | |
| 33 | + | e.Use(middleware.SecureRoutes(a)) | |
| 34 | 34 | ||
| 35 | 35 | // Color scheme detection for dark/light mode | |
| 36 | 36 | e.Use(middleware.ColorSchemeDetection) | |
| @@ -30,7 +30,7 @@ func RegisterRoutes(e *echo.Echo, a *server.App) *echo.Echo { | |||||
| 30 | e.Use(middleware.ErrorHandler) | 30 | e.Use(middleware.ErrorHandler) | ||
| 31 | 31 | ||||
| 32 | // Use middlewares | 32 | // Use middlewares | ||
| 33 | - | e.Use(middleware.SecureRoutes()) | 33 | + | e.Use(middleware.SecureRoutes(a)) |
| 34 | 34 | ||||
| 35 | // Color scheme detection for dark/light mode | 35 | // Color scheme detection for dark/light mode | ||
| 36 | e.Use(middleware.ColorSchemeDetection) | 36 | e.Use(middleware.ColorSchemeDetection) | ||
M internal/templating/models/html/fragments/menu.gohtml +45 -16
| @@ -1,3 +1,36 @@ | |||
| 1 | + | <script> | |
| 2 | + | function checkVersion(versionData) { | |
| 3 | + | var currentVersion = document | |
| 4 | + | .getElementById("actual-version") | |
| 5 | + | .textContent.trim(); | |
| 6 | + | // Extract the numeric part of the version string using a regular expression | |
| 7 | + | var fetchedVersionNumber = | |
| 8 | + | versionData["amd64"]["name"].match(/\d+\.\d+\.\d+/)[0]; | |
| 9 | + | ||
| 10 | + | if (currentVersion !== fetchedVersionNumber) { | |
| 11 | + | console.log("New version available:", fetchedVersionNumber); | |
| 12 | + | // Show the update-available span by removing the 'hidden' attribute | |
| 13 | + | document.getElementById("update-available").removeAttribute("hidden"); | |
| 14 | + | } else { | |
| 15 | + | console.log( | |
| 16 | + | "No new version. Current version is up-to-date:", | |
| 17 | + | currentVersion | |
| 18 | + | ); | |
| 19 | + | } | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | function fetchVersionInfo() { | |
| 23 | + | fetch("https://gordon-proxy.bnema.dev/version") | |
| 24 | + | .then((response) => response.json()) | |
| 25 | + | .then((data) => { | |
| 26 | + | checkVersion(data); // Pass the parsed JSON data to checkVersion | |
| 27 | + | }) | |
| 28 | + | .catch((error) => console.error("Error fetching version:", error)); | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | // Run fetchVersionInfo when the window loads | |
| 32 | + | window.onload = fetchVersionInfo; | |
| 33 | + | </script> | |
| 1 | 34 | <div | |
| 2 | 35 | id="menubar" | |
| 3 | 36 | class="w-full h-12 md:h-16 fixed top-0 left-0 bg-gordonmascot-lblue flex flex-row justify-evenly items-center px-4 IBMPlexSans"> | |
| @@ -7,9 +40,18 @@ | |||
| 7 | 40 | Gordon | |
| 8 | 41 | </h1> | |
| 9 | 42 | <span | |
| 10 | - | class="text-gordonmascot-mblue text-xs md:text-sm" | |
| 11 | - | >{{ .BuildVersion }}</span | |
| 12 | - | > | |
| 43 | + | id="actual-version" | |
| 44 | + | class="text-gordonmascot-mblue text-xs md:text-sm"> | |
| 45 | + | {{ .BuildVersion }} | |
| 46 | + | </span> | |
| 47 | + | <!-- if .LatestVersion is > to BuildVersion show arrow up --> | |
| 48 | + | <span | |
| 49 | + | hidden | |
| 50 | + | id="update-available" | |
| 51 | + | class="text-teal-200 text-xs md:text-sm" | |
| 52 | + | title="A new version is available" | |
| 53 | + | ><a href="{{ .LatestVersionURL }}"></a> | |
| 54 | + | </span> | |
| 13 | 55 | </div> | |
| 14 | 56 | <div class="w-full"> | |
| 15 | 57 | <ul | |
| @@ -35,16 +77,3 @@ | |||
| 35 | 77 | > | |
| 36 | 78 | </div> | |
| 37 | 79 | </div> | |
| 38 | - | ||
| 39 | - | <!-- <li class="" hidden> | |
| 40 | - | <i class="iconoir-dashboard-speed mr-2 text-3xl"></i> | |
| 41 | - | <a href="/admin">Dashboard</a> | |
| 42 | - | </li> | |
| 43 | - | <li class="flex items-center justify-start w-full text-gray-600" hidden> | |
| 44 | - | <i class="iconoir-community mr-2 text-3xl"></i> | |
| 45 | - | <a title="Disabled" href="#">Users</a> | |
| 46 | - | </li> | |
| 47 | - | <li class="flex items-center justify-start w-full text-gray-600" hidden> | |
| 48 | - | <i class="iconoir-database-settings mr-2 text-3xl"></i> | |
| 49 | - | <a title="Disabled" href="#">Settings</a> | |
| 50 | - | </li> --> | |
| @@ -1,3 +1,36 @@ | |||||
| 1 | + | <script> | |||
| 2 | + | function checkVersion(versionData) { | |||
| 3 | + | var currentVersion = document | |||
| 4 | + | .getElementById("actual-version") | |||
| 5 | + | .textContent.trim(); | |||
| 6 | + | // Extract the numeric part of the version string using a regular expression | |||
| 7 | + | var fetchedVersionNumber = | |||
| 8 | + | versionData["amd64"]["name"].match(/\d+\.\d+\.\d+/)[0]; | |||
| 9 | + | ||||
| 10 | + | if (currentVersion !== fetchedVersionNumber) { | |||
| 11 | + | console.log("New version available:", fetchedVersionNumber); | |||
| 12 | + | // Show the update-available span by removing the 'hidden' attribute | |||
| 13 | + | document.getElementById("update-available").removeAttribute("hidden"); | |||
| 14 | + | } else { | |||
| 15 | + | console.log( | |||
| 16 | + | "No new version. Current version is up-to-date:", | |||
| 17 | + | currentVersion | |||
| 18 | + | ); | |||
| 19 | + | } | |||
| 20 | + | } | |||
| 21 | + | ||||
| 22 | + | function fetchVersionInfo() { | |||
| 23 | + | fetch("https://gordon-proxy.bnema.dev/version") | |||
| 24 | + | .then((response) => response.json()) | |||
| 25 | + | .then((data) => { | |||
| 26 | + | checkVersion(data); // Pass the parsed JSON data to checkVersion | |||
| 27 | + | }) | |||
| 28 | + | .catch((error) => console.error("Error fetching version:", error)); | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | // Run fetchVersionInfo when the window loads | |||
| 32 | + | window.onload = fetchVersionInfo; | |||
| 33 | + | </script> | |||
| 1 | <div | 34 | <div | ||
| 2 | id="menubar" | 35 | id="menubar" | ||
| 3 | class="w-full h-12 md:h-16 fixed top-0 left-0 bg-gordonmascot-lblue flex flex-row justify-evenly items-center px-4 IBMPlexSans"> | 36 | class="w-full h-12 md:h-16 fixed top-0 left-0 bg-gordonmascot-lblue flex flex-row justify-evenly items-center px-4 IBMPlexSans"> | ||
| @@ -7,9 +40,18 @@ | |||||
| 7 | Gordon | 40 | Gordon | ||
| 8 | </h1> | 41 | </h1> | ||
| 9 | <span | 42 | <span | ||
| 10 | - | class="text-gordonmascot-mblue text-xs md:text-sm" | 43 | + | id="actual-version" |
| 11 | - | >{{ .BuildVersion }}</span | 44 | + | class="text-gordonmascot-mblue text-xs md:text-sm"> |
| 12 | - | > | 45 | + | {{ .BuildVersion }} |
| 46 | + | </span> | |||
| 47 | + | <!-- if .LatestVersion is > to BuildVersion show arrow up --> | |||
| 48 | + | <span | |||
| 49 | + | hidden | |||
| 50 | + | id="update-available" | |||
| 51 | + | class="text-teal-200 text-xs md:text-sm" | |||
| 52 | + | title="A new version is available" | |||
| 53 | + | ><a href="{{ .LatestVersionURL }}"></a> | |||
| 54 | + | </span> | |||
| 13 | </div> | 55 | </div> | ||
| 14 | <div class="w-full"> | 56 | <div class="w-full"> | ||
| 15 | <ul | 57 | <ul | ||
| @@ -35,16 +77,3 @@ | |||||
| 35 | > | 77 | > | ||
| 36 | </div> | 78 | </div> | ||
| 37 | </div> | 79 | </div> | ||
| 38 | - | ||||
| 39 | - | <!-- <li class="" hidden> | |||
| 40 | - | <i class="iconoir-dashboard-speed mr-2 text-3xl"></i> | |||
| 41 | - | <a href="/admin">Dashboard</a> | |||
| 42 | - | </li> | |||
| 43 | - | <li class="flex items-center justify-start w-full text-gray-600" hidden> | |||
| 44 | - | <i class="iconoir-community mr-2 text-3xl"></i> | |||
| 45 | - | <a title="Disabled" href="#">Users</a> | |||
| 46 | - | </li> | |||
| 47 | - | <li class="flex items-center justify-start w-full text-gray-600" hidden> | |||
| 48 | - | <i class="iconoir-database-settings mr-2 text-3xl"></i> | |||
| 49 | - | <a title="Disabled" href="#">Settings</a> | |||
| 50 | - | </li> --> | |||
M internal/templating/models/html/login/index.gohtml +0 -4
| @@ -8,10 +8,6 @@ | |||
| 8 | 8 | <meta name="keywords" content="{{ .Header.Meta.Keywords }}" /> | |
| 9 | 9 | <!-- Custom CSS + Tailwind --> | |
| 10 | 10 | <link rel="stylesheet" href="/assets/css/tailwind.css" /> | |
| 11 | - | <!-- Iconoir --> | |
| 12 | - | <link rel="stylesheet" href="/libs/iconoir.css" /> | |
| 13 | - | <!-- Alpine --> | |
| 14 | - | <script src="/libs/alpine.min.js"></script> | |
| 15 | 11 | <!-- HTMX min js --> | |
| 16 | 12 | <script src="/libs/htmx.min.js"></script> | |
| 17 | 13 | <!-- HTMX SSE --> | |
| @@ -8,10 +8,6 @@ | |||||
| 8 | <meta name="keywords" content="{{ .Header.Meta.Keywords }}" /> | 8 | <meta name="keywords" content="{{ .Header.Meta.Keywords }}" /> | ||
| 9 | <!-- Custom CSS + Tailwind --> | 9 | <!-- Custom CSS + Tailwind --> | ||
| 10 | <link rel="stylesheet" href="/assets/css/tailwind.css" /> | 10 | <link rel="stylesheet" href="/assets/css/tailwind.css" /> | ||
| 11 | - | <!-- Iconoir --> | |||
| 12 | - | <link rel="stylesheet" href="/libs/iconoir.css" /> | |||
| 13 | - | <!-- Alpine --> | |||
| 14 | - | <script src="/libs/alpine.min.js"></script> | |||
| 15 | <!-- HTMX min js --> | 11 | <!-- HTMX min js --> | ||
| 16 | <script src="/libs/htmx.min.js"></script> | 12 | <script src="/libs/htmx.min.js"></script> | ||
| 17 | <!-- HTMX SSE --> | 13 | <!-- HTMX SSE --> | ||
M internal/templating/render/html.go +4 -3
| @@ -11,9 +11,10 @@ import ( | |||
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | 13 | type Renderer struct { | |
| 14 | - | Template *template.Template | |
| 15 | - | ParseError error | |
| 16 | - | BuildVersion string | |
| 14 | + | Template *template.Template | |
| 15 | + | ParseError error | |
| 16 | + | BuildVersion string | |
| 17 | + | LatestVersion string | |
| 17 | 18 | } | |
| 18 | 19 | ||
| 19 | 20 | // Render function renders the template with the given data | |
| @@ -11,9 +11,10 @@ import ( | |||||
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| 13 | type Renderer struct { | 13 | type Renderer struct { | ||
| 14 | - | Template *template.Template | 14 | + | Template *template.Template |
| 15 | - | ParseError error | 15 | + | ParseError error |
| 16 | - | BuildVersion string | 16 | + | BuildVersion string |
| 17 | + | LatestVersion string | |||
| 17 | } | 18 | } | ||
| 18 | 19 | ||||
| 19 | // Render function renders the template with the given data | 20 | // Render function renders the template with the given data | ||
M internal/webui/public/assets/css/tailwind.css +20 -16
| @@ -636,10 +636,6 @@ video { | |||
| 636 | 636 | display: none; | |
| 637 | 637 | } | |
| 638 | 638 | ||
| 639 | - | .h-10 { | |
| 640 | - | height: 2.5rem; | |
| 641 | - | } | |
| 642 | - | ||
| 643 | 639 | .h-12 { | |
| 644 | 640 | height: 3rem; | |
| 645 | 641 | } | |
| @@ -680,10 +676,6 @@ video { | |||
| 680 | 676 | width: 41.666667%; | |
| 681 | 677 | } | |
| 682 | 678 | ||
| 683 | - | .w-72 { | |
| 684 | - | width: 18rem; | |
| 685 | - | } | |
| 686 | - | ||
| 687 | 679 | .w-full { | |
| 688 | 680 | width: 100%; | |
| 689 | 681 | } | |
| @@ -772,10 +764,6 @@ video { | |||
| 772 | 764 | border-radius: 0.25rem; | |
| 773 | 765 | } | |
| 774 | 766 | ||
| 775 | - | .rounded-lg { | |
| 776 | - | border-radius: 0.5rem; | |
| 777 | - | } | |
| 778 | - | ||
| 779 | 767 | .rounded-md { | |
| 780 | 768 | border-radius: 0.375rem; | |
| 781 | 769 | } | |
| @@ -1019,11 +1007,31 @@ video { | |||
| 1019 | 1007 | color: rgb(241 245 249 / var(--tw-text-opacity)); | |
| 1020 | 1008 | } | |
| 1021 | 1009 | ||
| 1010 | + | .text-teal-600 { | |
| 1011 | + | --tw-text-opacity: 1; | |
| 1012 | + | color: rgb(13 148 136 / var(--tw-text-opacity)); | |
| 1013 | + | } | |
| 1014 | + | ||
| 1022 | 1015 | .text-white { | |
| 1023 | 1016 | --tw-text-opacity: 1; | |
| 1024 | 1017 | color: rgb(255 255 255 / var(--tw-text-opacity)); | |
| 1025 | 1018 | } | |
| 1026 | 1019 | ||
| 1020 | + | .text-teal-300 { | |
| 1021 | + | --tw-text-opacity: 1; | |
| 1022 | + | color: rgb(94 234 212 / var(--tw-text-opacity)); | |
| 1023 | + | } | |
| 1024 | + | ||
| 1025 | + | .text-teal-400 { | |
| 1026 | + | --tw-text-opacity: 1; | |
| 1027 | + | color: rgb(45 212 191 / var(--tw-text-opacity)); | |
| 1028 | + | } | |
| 1029 | + | ||
| 1030 | + | .text-teal-200 { | |
| 1031 | + | --tw-text-opacity: 1; | |
| 1032 | + | color: rgb(153 246 228 / var(--tw-text-opacity)); | |
| 1033 | + | } | |
| 1034 | + | ||
| 1027 | 1035 | .shadow { | |
| 1028 | 1036 | --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); | |
| 1029 | 1037 | --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); | |
| @@ -1195,10 +1203,6 @@ video { | |||
| 1195 | 1203 | margin-left: 1rem; | |
| 1196 | 1204 | } | |
| 1197 | 1205 | ||
| 1198 | - | .md\:flex { | |
| 1199 | - | display: flex; | |
| 1200 | - | } | |
| 1201 | - | ||
| 1202 | 1206 | .md\:h-16 { | |
| 1203 | 1207 | height: 4rem; | |
| 1204 | 1208 | } | |
| @@ -636,10 +636,6 @@ video { | |||||
| 636 | display: none; | 636 | display: none; | ||
| 637 | } | 637 | } | ||
| 638 | 638 | ||||
| 639 | - | .h-10 { | |||
| 640 | - | height: 2.5rem; | |||
| 641 | - | } | |||
| 642 | - | ||||
| 643 | .h-12 { | 639 | .h-12 { | ||
| 644 | height: 3rem; | 640 | height: 3rem; | ||
| 645 | } | 641 | } | ||
| @@ -680,10 +676,6 @@ video { | |||||
| 680 | width: 41.666667%; | 676 | width: 41.666667%; | ||
| 681 | } | 677 | } | ||
| 682 | 678 | ||||
| 683 | - | .w-72 { | |||
| 684 | - | width: 18rem; | |||
| 685 | - | } | |||
| 686 | - | ||||
| 687 | .w-full { | 679 | .w-full { | ||
| 688 | width: 100%; | 680 | width: 100%; | ||
| 689 | } | 681 | } | ||
| @@ -772,10 +764,6 @@ video { | |||||
| 772 | border-radius: 0.25rem; | 764 | border-radius: 0.25rem; | ||
| 773 | } | 765 | } | ||
| 774 | 766 | ||||
| 775 | - | .rounded-lg { | |||
| 776 | - | border-radius: 0.5rem; | |||
| 777 | - | } | |||
| 778 | - | ||||
| 779 | .rounded-md { | 767 | .rounded-md { | ||
| 780 | border-radius: 0.375rem; | 768 | border-radius: 0.375rem; | ||
| 781 | } | 769 | } | ||
| @@ -1019,11 +1007,31 @@ video { | |||||
| 1019 | color: rgb(241 245 249 / var(--tw-text-opacity)); | 1007 | color: rgb(241 245 249 / var(--tw-text-opacity)); | ||
| 1020 | } | 1008 | } | ||
| 1021 | 1009 | ||||
| 1010 | + | .text-teal-600 { | |||
| 1011 | + | --tw-text-opacity: 1; | |||
| 1012 | + | color: rgb(13 148 136 / var(--tw-text-opacity)); | |||
| 1013 | + | } | |||
| 1014 | + | ||||
| 1022 | .text-white { | 1015 | .text-white { | ||
| 1023 | --tw-text-opacity: 1; | 1016 | --tw-text-opacity: 1; | ||
| 1024 | color: rgb(255 255 255 / var(--tw-text-opacity)); | 1017 | color: rgb(255 255 255 / var(--tw-text-opacity)); | ||
| 1025 | } | 1018 | } | ||
| 1026 | 1019 | ||||
| 1020 | + | .text-teal-300 { | |||
| 1021 | + | --tw-text-opacity: 1; | |||
| 1022 | + | color: rgb(94 234 212 / var(--tw-text-opacity)); | |||
| 1023 | + | } | |||
| 1024 | + | ||||
| 1025 | + | .text-teal-400 { | |||
| 1026 | + | --tw-text-opacity: 1; | |||
| 1027 | + | color: rgb(45 212 191 / var(--tw-text-opacity)); | |||
| 1028 | + | } | |||
| 1029 | + | ||||
| 1030 | + | .text-teal-200 { | |||
| 1031 | + | --tw-text-opacity: 1; | |||
| 1032 | + | color: rgb(153 246 228 / var(--tw-text-opacity)); | |||
| 1033 | + | } | |||
| 1034 | + | ||||
| 1027 | .shadow { | 1035 | .shadow { | ||
| 1028 | --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); | 1036 | --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); | ||
| 1029 | --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); | 1037 | --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); | ||
| @@ -1195,10 +1203,6 @@ video { | |||||
| 1195 | margin-left: 1rem; | 1203 | margin-left: 1rem; | ||
| 1196 | } | 1204 | } | ||
| 1197 | 1205 | ||||
| 1198 | - | .md\:flex { | |||
| 1199 | - | display: flex; | |||
| 1200 | - | } | |||
| 1201 | - | ||||
| 1202 | .md\:h-16 { | 1206 | .md\:h-16 { | ||
| 1203 | height: 4rem; | 1207 | height: 4rem; | ||
| 1204 | } | 1208 | } | ||