diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75562129f..ff9742044 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## v0.127
+
+### Changed
+
+- Refactored light and dark theme to use a single CSS bundle.
+
## v0.126
### Changed
diff --git a/ui/Makefile b/ui/Makefile
index 5eba1451e..6150ac622 100644
--- a/ui/Makefile
+++ b/ui/Makefile
@@ -23,8 +23,6 @@ $(NODE_PATH)/%: $(NODE_INSTALL)
@if [ ! -x $@ ]; then echo "missing script: $@" ; exit 1; fi
dist/index.html: $(NODE_INSTALL) $(NODE_PATH)/vite $(call rwildcard, public src, *)
- @rm -fr node_modules/.cache/eslint-loader
- sed -e '/:root,/d' -e 's/\[data-bs-theme="light"\] {/* {/' node_modules/bootstrap/scss/_root.scss | sed -n '1,/^}/p' > src/Styles/BootstrapRoot.scss
npm run build
.PHONY: build
diff --git a/ui/playwright.config.ts b/ui/playwright.config.ts
index fc906a96e..4a83bb8ae 100644
--- a/ui/playwright.config.ts
+++ b/ui/playwright.config.ts
@@ -14,6 +14,7 @@ export default defineConfig({
screenshot: "off",
video: "off",
trace: "off",
+ timezoneId: "UTC",
},
projects: [
{
diff --git a/ui/src/App.tsx b/ui/src/App.tsx
index 335b90afd..e12dd1c17 100644
--- a/ui/src/App.tsx
+++ b/ui/src/App.tsx
@@ -16,9 +16,9 @@ import { BodyTheme, ThemeContext } from "Components/Theme";
import type { UIDefaults } from "Models/UI";
import { ErrorBoundary } from "./ErrorBoundary";
-import "Styles/ResetCSS.scss";
import "Styles/FontBundle.scss";
import "Styles/App.scss";
+import "Styles/Theme.scss";
const Grid = React.lazy(() => import("Components/Grid"));
const NavBar = React.lazy(() => import("Components/NavBar"));
diff --git a/ui/src/Components/Theme/index.test.tsx b/ui/src/Components/Theme/index.test.tsx
index 31f551b1a..b36abb650 100644
--- a/ui/src/Components/Theme/index.test.tsx
+++ b/ui/src/Components/Theme/index.test.tsx
@@ -11,6 +11,7 @@ const context = {
beforeEach(() => {
document.body.classList.remove("theme-light");
document.body.classList.remove("theme-dark");
+ document.documentElement.removeAttribute("data-bs-theme");
jest.spyOn(React, "useContext").mockImplementation(() => {
return context;
@@ -23,21 +24,27 @@ afterEach(() => {
describe("", () => {
it("uses light theme when ThemeContext->isDark is false", async () => {
- // Verifies body class is set to theme-light when isDark is false
+ // Verifies body class and data-bs-theme attribute are set for light theme when isDark is false
context.isDark = false;
await act(async () => {
render();
});
expect(document.body.classList.contains("theme-light")).toEqual(true);
+ expect(document.documentElement.getAttribute("data-bs-theme")).toEqual(
+ "light",
+ );
});
it("uses dark theme when ThemeContext->isDark is true", async () => {
- // Verifies body class is set to theme-dark when isDark is true
+ // Verifies body class and data-bs-theme attribute are set for dark theme when isDark is true
context.isDark = true;
await act(async () => {
render();
});
expect(document.body.classList.contains("theme-dark")).toEqual(true);
+ expect(document.documentElement.getAttribute("data-bs-theme")).toEqual(
+ "dark",
+ );
});
it("updates theme when ThemeContext->isDark is updated", async () => {
@@ -59,5 +66,8 @@ describe("", () => {
});
expect(document.body.classList.contains("theme-light")).toEqual(true);
+ expect(document.documentElement.getAttribute("data-bs-theme")).toEqual(
+ "light",
+ );
});
});
diff --git a/ui/src/Components/Theme/index.tsx b/ui/src/Components/Theme/index.tsx
index 6890ffa28..f52b5c634 100644
--- a/ui/src/Components/Theme/index.tsx
+++ b/ui/src/Components/Theme/index.tsx
@@ -1,45 +1,7 @@
import React, { FC, useEffect } from "react";
-import ReactDOM from "react-dom";
import type { StylesConfig } from "react-select/dist/declarations/src/styles";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faSun } from "@fortawesome/free-solid-svg-icons/faSun";
-
-const DarkTheme = React.lazy(() => import("Styles/DarkTheme"));
-const LightTheme = React.lazy(() => import("Styles/LightTheme"));
-
-const Placeholder = () => {
- return ReactDOM.createPortal(
-
-
-
,
- document.body,
- );
-};
-
export interface ThemeCtx {
isDark: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -59,15 +21,16 @@ const BodyTheme: FC = () => {
const context = React.useContext(ThemeContext);
useEffect(() => {
+ document.documentElement.setAttribute(
+ "data-bs-theme",
+ context.isDark ? "dark" : "light",
+ );
+ // TODO: this should be removed when not needed
document.body.classList.toggle("theme-dark", context.isDark);
document.body.classList.toggle("theme-light", !context.isDark);
}, [context.isDark]);
- return (
- }>
- {context.isDark ? : }
-
- );
+ return null;
};
export { BodyTheme, ThemeContext };
diff --git a/ui/src/Styles/BootstrapRoot.scss b/ui/src/Styles/BootstrapRoot.scss
deleted file mode 100644
index 9c672406a..000000000
--- a/ui/src/Styles/BootstrapRoot.scss
+++ /dev/null
@@ -1,129 +0,0 @@
-* {
- // Note: Custom variable values only support SassScript inside `#{}`.
-
- // Colors
- //
- // Generate palettes for full colors, grays, and theme colors.
-
- @each $color, $value in $colors {
- --#{$prefix}#{$color}: #{$value};
- }
-
- @each $color, $value in $grays {
- --#{$prefix}gray-#{$color}: #{$value};
- }
-
- @each $color, $value in $theme-colors {
- --#{$prefix}#{$color}: #{$value};
- }
-
- @each $color, $value in $theme-colors-rgb {
- --#{$prefix}#{$color}-rgb: #{$value};
- }
-
- @each $color, $value in $theme-colors-text {
- --#{$prefix}#{$color}-text-emphasis: #{$value};
- }
-
- @each $color, $value in $theme-colors-bg-subtle {
- --#{$prefix}#{$color}-bg-subtle: #{$value};
- }
-
- @each $color, $value in $theme-colors-border-subtle {
- --#{$prefix}#{$color}-border-subtle: #{$value};
- }
-
- --#{$prefix}white-rgb: #{to-rgb($white)};
- --#{$prefix}black-rgb: #{to-rgb($black)};
-
- // Fonts
-
- // Note: Use `inspect` for lists so that quoted items keep the quotes.
- // See https://github.com/sass/sass/issues/2383#issuecomment-336349172
- --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};
- --#{$prefix}font-monospace: #{inspect($font-family-monospace)};
- --#{$prefix}gradient: #{$gradient};
-
- // Root and body
- // scss-docs-start root-body-variables
- @if $font-size-root != null {
- --#{$prefix}root-font-size: #{$font-size-root};
- }
- --#{$prefix}body-font-family: #{inspect($font-family-base)};
- @include rfs($font-size-base, --#{$prefix}body-font-size);
- --#{$prefix}body-font-weight: #{$font-weight-base};
- --#{$prefix}body-line-height: #{$line-height-base};
- @if $body-text-align != null {
- --#{$prefix}body-text-align: #{$body-text-align};
- }
-
- --#{$prefix}body-color: #{$body-color};
- --#{$prefix}body-color-rgb: #{to-rgb($body-color)};
- --#{$prefix}body-bg: #{$body-bg};
- --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};
-
- --#{$prefix}emphasis-color: #{$body-emphasis-color};
- --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};
-
- --#{$prefix}secondary-color: #{$body-secondary-color};
- --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};
- --#{$prefix}secondary-bg: #{$body-secondary-bg};
- --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};
-
- --#{$prefix}tertiary-color: #{$body-tertiary-color};
- --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};
- --#{$prefix}tertiary-bg: #{$body-tertiary-bg};
- --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};
- // scss-docs-end root-body-variables
-
- --#{$prefix}heading-color: #{$headings-color};
-
- --#{$prefix}link-color: #{$link-color};
- --#{$prefix}link-color-rgb: #{to-rgb($link-color)};
- --#{$prefix}link-decoration: #{$link-decoration};
-
- --#{$prefix}link-hover-color: #{$link-hover-color};
- --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};
-
- @if $link-hover-decoration != null {
- --#{$prefix}link-hover-decoration: #{$link-hover-decoration};
- }
-
- --#{$prefix}code-color: #{$code-color};
- --#{$prefix}highlight-color: #{$mark-color};
- --#{$prefix}highlight-bg: #{$mark-bg};
-
- // scss-docs-start root-border-var
- --#{$prefix}border-width: #{$border-width};
- --#{$prefix}border-style: #{$border-style};
- --#{$prefix}border-color: #{$border-color};
- --#{$prefix}border-color-translucent: #{$border-color-translucent};
-
- --#{$prefix}border-radius: #{$border-radius};
- --#{$prefix}border-radius-sm: #{$border-radius-sm};
- --#{$prefix}border-radius-lg: #{$border-radius-lg};
- --#{$prefix}border-radius-xl: #{$border-radius-xl};
- --#{$prefix}border-radius-xxl: #{$border-radius-xxl};
- --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency
- --#{$prefix}border-radius-pill: #{$border-radius-pill};
- // scss-docs-end root-border-var
-
- --#{$prefix}box-shadow: #{$box-shadow};
- --#{$prefix}box-shadow-sm: #{$box-shadow-sm};
- --#{$prefix}box-shadow-lg: #{$box-shadow-lg};
- --#{$prefix}box-shadow-inset: #{$box-shadow-inset};
-
- // Focus styles
- // scss-docs-start root-focus-variables
- --#{$prefix}focus-ring-width: #{$focus-ring-width};
- --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
- --#{$prefix}focus-ring-color: #{$focus-ring-color};
- // scss-docs-end root-focus-variables
-
- // scss-docs-start root-form-validation-variables
- --#{$prefix}form-valid-color: #{$form-valid-color};
- --#{$prefix}form-valid-border-color: #{$form-valid-border-color};
- --#{$prefix}form-invalid-color: #{$form-invalid-color};
- --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};
- // scss-docs-end root-form-validation-variables
-}
diff --git a/ui/src/Styles/Components/_Accordion.scss b/ui/src/Styles/Components/_Accordion.scss
index c7620b362..875d9aa58 100644
--- a/ui/src/Styles/Components/_Accordion.scss
+++ b/ui/src/Styles/Components/_Accordion.scss
@@ -1,11 +1,11 @@
.accordion-item {
- border: 1px solid $accordion-border-color;
+ border: 1px solid var(--karma-accordion-border-color);
.accordion-header {
overflow: unset;
.accordion-button:not(.collapsed) {
- color: $body-color;
+ color: var(--bs-body-color);
}
}
}
diff --git a/ui/src/Styles/Components/_Alert.scss b/ui/src/Styles/Components/_Alert.scss
index 2b71227a4..da0b64330 100644
--- a/ui/src/Styles/Components/_Alert.scss
+++ b/ui/src/Styles/Components/_Alert.scss
@@ -1,9 +1,9 @@
.components-grid-alertgrid-alertgroup-alert.list-group-item {
- background-color: $alert-bg;
+ background-color: var(--karma-alert-bg);
border-width: 3px;
line-height: 1rem;
}
.components-grid-alertgrid-card {
- background-color: $alert-bg !important;
+ background-color: var(--karma-alert-bg) !important;
}
diff --git a/ui/src/Styles/Components/_AlertGrid.scss b/ui/src/Styles/Components/_AlertGrid.scss
index a5565d8d6..99a7999af 100644
--- a/ui/src/Styles/Components/_AlertGrid.scss
+++ b/ui/src/Styles/Components/_AlertGrid.scss
@@ -1,6 +1,6 @@
.components-grid-swimlane {
font-size: 1.4rem;
- background-color: $grid-swimlane-bg;
+ background-color: var(--karma-grid-swimlane-bg);
color: $white;
--bs-secondary-color: #{rgba($white, .75)};
margin-left: 0.3rem;
diff --git a/ui/src/Styles/Components/_AlertGroup.scss b/ui/src/Styles/Components/_AlertGroup.scss
index 326081403..ae9a11447 100644
--- a/ui/src/Styles/Components/_AlertGroup.scss
+++ b/ui/src/Styles/Components/_AlertGroup.scss
@@ -11,11 +11,11 @@
}
.card-footer.components-grid-alertgrid-alertgroup-footer {
- background-color: $alertgroup-footer-bg;
+ background-color: var(--karma-alertgroup-footer-bg);
}
.card-body.components-grid-alertgrid-card {
- background-color: $alertgroup-body-bg !important;
+ background-color: var(--karma-alertgroup-body-bg) !important;
}
.components-label:not(:last-child),
diff --git a/ui/src/Styles/Components/_AlertHistory.scss b/ui/src/Styles/Components/_AlertHistory.scss
index 7680bfb87..cb8ae016a 100644
--- a/ui/src/Styles/Components/_AlertHistory.scss
+++ b/ui/src/Styles/Components/_AlertHistory.scss
@@ -53,10 +53,10 @@ svg.alert-history {
}
}
&.inactive {
- fill: $alert-history-inactive;
+ fill: var(--karma-alert-history-inactive);
}
&.fetching {
- fill: $alert-history-inactive;
+ fill: var(--karma-alert-history-inactive);
animation-timing-function: ease-out;
animation-duration: 12s;
animation-iteration-count: infinite;
diff --git a/ui/src/Styles/Components/_Annotation.scss b/ui/src/Styles/Components/_Annotation.scss
index 4106b55c4..23c54bfd9 100644
--- a/ui/src/Styles/Components/_Annotation.scss
+++ b/ui/src/Styles/Components/_Annotation.scss
@@ -1,13 +1,13 @@
.components-grid-annotation {
font-size: 0.85rem;
- color: $body-color;
+ color: var(--bs-body-color);
}
.components-grid-annotation-link {
text-decoration: none;
- color: $link-color;
+ color: var(--karma-link-color);
&.border {
- border-color: $annotation-link-border !important;
+ border-color: var(--karma-annotation-link-border) !important;
}
}
.components-grid-annotation-link:hover {
diff --git a/ui/src/Styles/Components/_BaseLabel.scss b/ui/src/Styles/Components/_BaseLabel.scss
index 9d7272f47..8c16f4dcb 100644
--- a/ui/src/Styles/Components/_BaseLabel.scss
+++ b/ui/src/Styles/Components/_BaseLabel.scss
@@ -26,46 +26,46 @@
.btn-default,
.bg-default {
- background-color: $color-default;
+ background-color: var(--karma-color-default);
}
.border-default {
- border: 1px solid $color-default;
+ border: 1px solid var(--karma-color-default);
}
.components-label:not(.rounded-pill) {
&.bg-default,
&.btn-default {
- border: 1px solid darken($color-default, 2%);
+ border: 1px solid var(--karma-color-default);
}
&.bg-primary,
&.btn-primary {
- border: 1px solid lighten($primary, 2%);
+ border: 1px solid var(--karma-label-primary-border);
}
&.bg-secondary,
&.btn-secondary {
- border: 1px solid darken($secondary, 1%);
- background-color: darken($secondary, 2%) !important;
+ border: 1px solid var(--karma-label-secondary-border);
+ background-color: var(--karma-label-secondary-bg) !important;
}
&.bg-success,
&.btn-success {
- border: 1px solid darken($success, 2%);
+ border: 1px solid var(--karma-label-success-border);
}
&.bg-danger,
&.btn-danger {
- border: 1px solid lighten($danger, 2%);
+ border: 1px solid var(--karma-label-danger-border);
}
&.bg-warning,
&.btn-warning {
- border: 1px solid lighten($warning, 3%);
+ border: 1px solid var(--karma-label-warning-border);
}
&.bg-info,
&.btn-info {
- border: 1px solid darken($info, 2%);
+ border: 1px solid var(--karma-label-info-border);
}
&.bg-dark,
&.btn-dark {
- border: 1px solid darken($dark, 2%);
+ border: 1px solid var(--karma-label-dark-border);
}
}
diff --git a/ui/src/Styles/Components/_DateTimeSelect.scss b/ui/src/Styles/Components/_DateTimeSelect.scss
index da0e99e06..bf17f0746 100644
--- a/ui/src/Styles/Components/_DateTimeSelect.scss
+++ b/ui/src/Styles/Components/_DateTimeSelect.scss
@@ -1,8 +1,11 @@
.components-date-range {
- --rdp-cell-size: 40px;
- --rdp-accent-color: #{$secondary};
- --rdp-selected-border: none;
- --rdp-range_middle-background-color: #{$light};
+ &.rdp-root {
+ --rdp-cell-size: 40px;
+ --rdp-accent-color: var(--bs-secondary);
+ --rdp-selected-border: none;
+ --rdp-today-color: var(--bs-secondary);
+ --rdp-range_middle-background-color: var(--bs-light);
+ }
.rdp-day_button {
padding: 0;
@@ -15,7 +18,7 @@
.rdp-button_previous,
.rdp-button_next {
- color: $secondary;
+ color: var(--bs-secondary);
}
.rdp-day {
@@ -34,7 +37,7 @@
&:hover,
&:active,
&:focus {
- background-color: $light;
+ background-color: var(--bs-light);
}
&.rdp-disabled {
@@ -59,12 +62,12 @@
}
&:not(.rdp-disabled):not(.rdp-range_middle):not(.rdp-selected):hover {
- background-color: $light;
+ background-color: var(--bs-light);
}
}
.rdp-day.rdp-disabled .rdp-day_button {
- color: $secondary;
+ color: var(--bs-secondary);
}
.rdp-day.rdp-today .rdp-day_button {
@@ -80,12 +83,12 @@
.rdp-day.rdp-selected.rdp-range_start .rdp-day_button,
.rdp-day.rdp-selected.rdp-range_end .rdp-day_button {
font-weight: 600;
- background-color: $primary;
+ background-color: var(--bs-primary);
&:hover,
&:active,
&:focus {
- background-color: $primary;
+ background-color: var(--bs-primary);
}
}
@@ -100,12 +103,12 @@
}
.rdp-day.rdp-selected:not(.rdp-range_middle) .rdp-day_button {
- background-color: $primary;
- color: $white;
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
}
.rdp-day.rdp-selected.rdp-range_middle:not(.rdp-range_start):not(.rdp-range_end) .rdp-day_button {
- background-color: $light;
- color: $components-date-range-sub-color;
+ background-color: var(--bs-light);
+ color: var(--karma-components-date-range-sub-color);
}
}
diff --git a/ui/src/Styles/Components/_Fetcher.scss b/ui/src/Styles/Components/_Fetcher.scss
index a665eb69c..b54f227ac 100644
--- a/ui/src/Styles/Components/_Fetcher.scss
+++ b/ui/src/Styles/Components/_Fetcher.scss
@@ -25,13 +25,13 @@ $pixSize: math.div($fetcherWidth, 5);
}
&.fetching > .dot {
- background-color: $warning;
+ background-color: var(--bs-warning);
}
&.processing > .dot {
- background-color: $success;
+ background-color: var(--bs-success);
}
&.retrying > .dot {
- background-color: $danger;
+ background-color: var(--bs-danger);
}
.dot {
@@ -45,7 +45,7 @@ $pixSize: math.div($fetcherWidth, 5);
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
- background-color: $white;
+ background-color: var(--bs-white);
animation-duration: 0.9s;
animation-iteration-count: infinite;
diff --git a/ui/src/Styles/Components/_FilterInput.scss b/ui/src/Styles/Components/_FilterInput.scss
index 447a6bf3c..e52e46a52 100644
--- a/ui/src/Styles/Components/_FilterInput.scss
+++ b/ui/src/Styles/Components/_FilterInput.scss
@@ -2,7 +2,7 @@
border-top: 0;
border-left: 0;
border-right: 0;
- border-bottom: $border-width solid $filterinput-border;
+ border-bottom: $border-width solid var(--karma-filterinput-border);
.bg-inherit {
background-color: unset;
@@ -39,10 +39,11 @@ input.components-filterinput-wrapper {
.bg-focused {
@supports (backdrop-filter: blur(12px)) {
- background-color: rgba($bg-focused, 0.5);
+ // TODO: why is this hardcoding colors?
+ background-color: rgba(var(--karma-bg-focused-rgb, 81, 113, 132), 0.5);
}
@supports not (backdrop-filter: blur(12px)) {
- background-color: $bg-focused;
+ background-color: var(--karma-bg-focused);
}
}
diff --git a/ui/src/Styles/Components/_FilterInputLabel.scss b/ui/src/Styles/Components/_FilterInputLabel.scss
index 2b0356383..51deb401d 100644
--- a/ui/src/Styles/Components/_FilterInputLabel.scss
+++ b/ui/src/Styles/Components/_FilterInputLabel.scss
@@ -11,13 +11,13 @@
}
& > .editing {
- background-color: $filter-input-hoover-bg;
- color: $filter-input-hoover-color;
+ background-color: var(--karma-filter-input-hoover-bg);
+ color: var(--karma-filter-input-hoover-color);
}
&:hover {
- background-color: $filter-input-hoover-bg;
- color: $filter-input-hoover-color;
+ background-color: var(--karma-filter-input-hoover-bg);
+ color: var(--karma-filter-input-hoover-color);
border-radius: 0.25rem;
}
}
@@ -49,32 +49,31 @@ button.btn.components-filteredinputlabel {
button.components-label.btn {
&.btn-default:hover {
- background-color: $color-default;
+ background-color: var(--karma-color-default);
}
&.btn-primary:hover {
- background-color: $primary;
+ background-color: var(--bs-primary);
}
&.btn-secondary:hover {
- background-color: $secondary;
+ background-color: var(--bs-secondary);
}
&.btn-success:hover {
- background-color: $success;
+ background-color: var(--bs-success);
}
&.btn-info:hover {
- background-color: $info;
+ background-color: var(--bs-info);
}
&.btn-warning:hover {
- background-color: $warning;
+ background-color: var(--bs-warning);
}
&.btn-danger:hover {
- background-color: $danger;
+ background-color: var(--bs-danger);
}
&.btn-light:hover {
- background-color: $light;
+ background-color: var(--bs-light);
}
&.btn-dark:hover {
- // same as in Theme.scss
- background-color: $dark;
+ background-color: var(--bs-dark);
}
}
diff --git a/ui/src/Styles/Components/_InputRange.scss b/ui/src/Styles/Components/_InputRange.scss
index 182429b92..9ab091001 100644
--- a/ui/src/Styles/Components/_InputRange.scss
+++ b/ui/src/Styles/Components/_InputRange.scss
@@ -1,16 +1,20 @@
.input-range-track {
border-radius: 0.3rem;
height: 0.3rem;
- background-color: $input-range-track-background;
+ background-color: var(--karma-input-range-track-background);
}
.input-range-thumb {
- color: $input-range-thumb-font-color;
+ color: var(--karma-input-range-thumb-font-color);
font-size: 0.8rem;
border-radius: 0.5rem;
height: 1.2rem;
min-width: 1.2rem;
padding-left: 0.3rem;
padding-right: 0.3rem;
- background-color: $primary;
+ background-color: var(--bs-primary);
+
+ &:focus {
+ outline: none;
+ }
}
diff --git a/ui/src/Styles/Components/_LabelWithPercent.scss b/ui/src/Styles/Components/_LabelWithPercent.scss
index 08d373366..2fcebfd0d 100644
--- a/ui/src/Styles/Components/_LabelWithPercent.scss
+++ b/ui/src/Styles/Components/_LabelWithPercent.scss
@@ -6,7 +6,7 @@
.components-labelWithPercent-progress.progress {
height: 2px;
margin-top: 2px;
- background-color: darken($light, 10%);
+ background-color: var(--karma-progress-bg);
}
.components-labelWithPercent-progress.progress > .progress-bar {
diff --git a/ui/src/Styles/Components/_ManagedSilence.scss b/ui/src/Styles/Components/_ManagedSilence.scss
index 153dd46f7..ace1928d4 100644
--- a/ui/src/Styles/Components/_ManagedSilence.scss
+++ b/ui/src/Styles/Components/_ManagedSilence.scss
@@ -1,15 +1,16 @@
.components-managed-silence {
&.card {
+ background-color: var(--karma-silence-bg);
border-left-width: 3px;
- border-left-color: $silence-border;
+ border-left-color: var(--karma-silence-border);
}
.silence-detail {
- color: $silence-color;
+ color: var(--karma-silence-color);
}
.silence-id {
- color: $silence-id;
+ color: var(--karma-silence-id);
}
.silence-matcher-equal {
@@ -21,7 +22,7 @@
}
.components-managed-silence-comment {
- color: $silence-comment-color;
+ color: var(--karma-silence-comment-color);
line-height: 1.4rem;
font-size: 0.85rem;
}
diff --git a/ui/src/Styles/Components/_Modal.scss b/ui/src/Styles/Components/_Modal.scss
index 1c1473061..f2ba143f4 100644
--- a/ui/src/Styles/Components/_Modal.scss
+++ b/ui/src/Styles/Components/_Modal.scss
@@ -1,7 +1,7 @@
.components-tab-inactive {
&:hover {
- color: $white;
- background-color: $secondary;
+ color: var(--bs-white);
+ background-color: var(--bs-secondary);
}
}
diff --git a/ui/src/Styles/Components/_NavBar.scss b/ui/src/Styles/Components/_NavBar.scss
index a6c906b93..246b4fe17 100644
--- a/ui/src/Styles/Components/_NavBar.scss
+++ b/ui/src/Styles/Components/_NavBar.scss
@@ -1,5 +1,13 @@
.navbar {
- --bs-secondary-color: #{rgba($white, .75)};
+ // TODO: is there a cleaner way to do this? Ideally we should only overwrite what's really needed.
+ // Reset Bootstrap 5.3 color mode inheritance for dropdowns inside navbar
+ --bs-body-bg: #{$white};
+ --bs-body-color: #{$body-color};
+ --bs-dropdown-bg: #{$white};
+ --bs-dropdown-color: #{$body-color};
+ --bs-dropdown-link-color: #{$gray-700};
+ --bs-dropdown-link-hover-color: #{$white};
+ --bs-dropdown-link-hover-bg: #{$primary};
@supports (backdrop-filter: blur(12px)) {
background-color: rgba($primary, 0.85);
@@ -31,10 +39,10 @@
&:hover {
border-radius: 0.4rem;
@supports (backdrop-filter: blur(12px)) {
- background-color: rgba($bg-focused, 0.5);
+ background-color: rgba(var(--karma-bg-focused-rgb, 81, 113, 132), 0.5);
}
@supports not (backdrop-filter: blur(12px)) {
- background-color: $bg-focused;
+ background-color: var(--karma-bg-focused);
}
}
}
diff --git a/ui/src/Styles/Components/_Placeholder.scss b/ui/src/Styles/Components/_Placeholder.scss
index 9dbf97154..bc9151920 100644
--- a/ui/src/Styles/Components/_Placeholder.scss
+++ b/ui/src/Styles/Components/_Placeholder.scss
@@ -1,3 +1,3 @@
.text-placeholder {
- color: $placeholder-color;
+ color: var(--karma-placeholder-color);
}
diff --git a/ui/src/Styles/Components/_Toast.scss b/ui/src/Styles/Components/_Toast.scss
index 2a5445df0..565b5cdeb 100644
--- a/ui/src/Styles/Components/_Toast.scss
+++ b/ui/src/Styles/Components/_Toast.scss
@@ -8,7 +8,7 @@
max-width: 500px;
code {
- color: $warning;
+ color: var(--bs-warning);
}
}
@@ -22,11 +22,11 @@
.bg-toast {
@supports (backdrop-filter: blur(12px)) {
- background-color: rgba(darken($dark, 5%), 0.85);
+ background-color: rgba(var(--karma-toast-bg-rgb, 21, 21, 21), 0.85);
backdrop-filter: saturate(50%) blur(12px);
}
@supports not (backdrop-filter: blur(12px)) {
- background-color: darken($dark, 5%);
+ background-color: var(--karma-toast-bg);
}
}
diff --git a/ui/src/Styles/Components/_WithClick.scss b/ui/src/Styles/Components/_WithClick.scss
index c750a3ea8..a9f61adb0 100644
--- a/ui/src/Styles/Components/_WithClick.scss
+++ b/ui/src/Styles/Components/_WithClick.scss
@@ -15,7 +15,7 @@
pointer-events: none;
background-image: radial-gradient(
circle,
- $with-click-default 10%,
+ var(--karma-with-click-default) 10%,
transparent 10.01%
);
background-repeat: no-repeat;
@@ -28,7 +28,7 @@
&.with-click-dark:after {
background-image: radial-gradient(
circle,
- $with-click-dark 10%,
+ var(--karma-with-click-dark) 10%,
transparent 10.01%
);
}
@@ -36,7 +36,7 @@
&.with-click-light:after {
background-image: radial-gradient(
circle,
- $with-click-light 10%,
+ var(--karma-with-click-light) 10%,
transparent 10.01%
);
}
diff --git a/ui/src/Styles/DarkTheme.scss b/ui/src/Styles/DarkTheme.scss
deleted file mode 100644
index bdf4e17c7..000000000
--- a/ui/src/Styles/DarkTheme.scss
+++ /dev/null
@@ -1,125 +0,0 @@
-$lead-font-weight: 400;
-
-// custom "dark" color, little less dark than flatly
-$blue: #455a64;
-// default is ~0.97rem
-$font-size-base: 1rem;
-
-$enable-shadows: true;
-
-$btn-box-shadow: 0;
-$btn-focus-box-shadow: 0;
-$btn-active-box-shadow: 0;
-
-$tooltip-max-width: 400px;
-
-@import "./Fonts";
-@import "bootswatch/dist/darkly/variables";
-
-$dark: darken($dark, 4%);
-
-// revert to bootswatch 4.3.1 colors but adjust a bit so it doesn't end
-// up with same color as modal content background
-$light: lighten($gray-800, 5%);
-
-// make links light gray by default instead of green
-$link-color: $gray-400;
-
-$form-check-indicator-bg: $gray-100;
-$form-check-indicator-checked: $blue;
-$form-check-indicator-disabled-bg: $gray-700;
-$form-check-indicator-checked-disabled-bg: $gray-700;
-
-$navbar-dark-brand-color: $navbar-dark-color;
-$navbar-dark-brand-hover-color: $gray-200;
-$navbar-dark-hover-color: $gray-200;
-$navbar-dark-active-color: $gray-200;
-
-// fix active tab color, for some reason it ends up with $primary as bg color
-$nav-tabs-link-active-bg: $gray-800;
-
-// pagination tweaks
-$pagination-color: $white;
-$pagination-bg: $gray-700;
-$pagination-hover-color: $white;
-$pagination-hover-bg: $blue;
-$pagination-active-bg: $pagination-hover-bg;
-$pagination-disabled-color: $white;
-$pagination-disabled-bg: darken($gray-800, 2%);
-
-$input-color: $white;
-$input-bg: $secondary;
-$input-disabled-bg: $gray-800;
-$input-group-addon-bg: $gray-800;
-$input-border-color: $secondary;
-
-$card-cap-bg: inherit;
-
-$progress-bg: $black;
-
-$dropdown-bg: darken($gray-800, 2%);
-
-$with-click-default: $white;
-$with-click-dark: $white;
-$with-click-light: $dark;
-
-$accordion-icon-active-color: $body-color;
-$accordion-bg: $gray-800;
-$accordion-button-bg: $gray-700;
-$accordion-button-active-bg: $gray-700;
-$accordion-border-color: lighten($gray-700, 5%);
-
-$table-bg: transparent;
-$table-accent-bg: transparent;
-
-$card-cap-bg: inherit;
-
-$kbd-color: $white;
-$kbd-bg: $dark;
-
-$body-secondary-color: $gray-600;
-
-@import "./RebootlessBootstrap";
-@import "bootswatch/dist/darkly/bootswatch";
-
-$alert-bg: $list-group-bg;
-$alert-history-inactive: lighten($gray-700, 2%);
-$alertgroup-body-bg: lighten($gray-700, 5%);
-$alertgroup-footer-bg: lighten($gray-700, 2%);
-$silence-id: $white;
-$silence-color: $white;
-$silence-bg: lighten($gray-900, 4%);
-$silence-border: $black;
-$silence-comment-color: $gray-400;
-$accordion-active-bg: $gray-700;
-$filter-input-hoover-bg: $gray-700;
-$filter-input-hoover-color: $white;
-$placeholder-color: $gray-600;
-$filterinput-border: $navbar-dark-color;
-$grid-swimlane-bg: lighten($dark, 2%);
-$bg-focused: darken($blue, 5%);
-$annotation-link-border: $secondary;
-
-$components-date-range-sub-color: $white;
-
-$input-range-track-background: $secondary;
-$input-range-thumb-font-color: $white;
-
-$color-default: #708090;
-
-@import "./BootstrapRoot.scss";
-@import "./Components";
-
-.badge,
-.modal-content {
- color: $white;
-}
-
-a {
- color: $link-color;
-}
-
-button.btn {
- --bs-btn-active-border-color: transparent;
- --bs-btn-hover-border-color: transparent;
-}
diff --git a/ui/src/Styles/DarkTheme.tsx b/ui/src/Styles/DarkTheme.tsx
deleted file mode 100644
index 88990c9e1..000000000
--- a/ui/src/Styles/DarkTheme.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { FC } from "react";
-
-import "./DarkThemeLoader.scss";
-
-const DarkTheme: FC = () => null;
-
-export default DarkTheme;
diff --git a/ui/src/Styles/DarkThemeLoader.scss b/ui/src/Styles/DarkThemeLoader.scss
deleted file mode 100644
index 30441d5db..000000000
--- a/ui/src/Styles/DarkThemeLoader.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.theme-dark {
- @import "./DarkTheme";
-}
diff --git a/ui/src/Styles/Percy.scss b/ui/src/Styles/E2E.scss
similarity index 80%
rename from ui/src/Styles/Percy.scss
rename to ui/src/Styles/E2E.scss
index c96cbe0b2..edb6015a3 100644
--- a/ui/src/Styles/Percy.scss
+++ b/ui/src/Styles/E2E.scss
@@ -1,7 +1,5 @@
@import "./App";
-@import "./LightThemeLoader";
-@import "./DarkThemeLoader";
-@import "./ResetCSS";
+@import "./Theme";
.dropdown-menu {
position: relative !important;
diff --git a/ui/src/Styles/LightTheme.scss b/ui/src/Styles/LightTheme.scss
deleted file mode 100644
index 9fc90187d..000000000
--- a/ui/src/Styles/LightTheme.scss
+++ /dev/null
@@ -1,107 +0,0 @@
-$lead-font-weight: 400;
-
-// custom "dark" color, little less dark than flatly
-$blue: #455a64;
-// default is ~0.97rem
-$font-size-base: 1rem;
-
-// make dark darker, default it's $gray-700
-$dark: #3b4247;
-
-$enable-shadows: true;
-
-$btn-box-shadow: 0;
-$btn-focus-box-shadow: 0;
-$btn-active-box-shadow: 0;
-
-$tooltip-max-width: 400px;
-
-@import "./Fonts";
-@import "bootswatch/dist/flatly/variables";
-
-// make links light gray by default instead of green
-$link-color: $gray-700;
-
-$navbar-dark-brand-color: $navbar-dark-color;
-$navbar-dark-brand-hover-color: $gray-200;
-$navbar-dark-hover-color: $gray-200;
-$navbar-dark-active-color: $gray-200;
-
-// fix active tab color, for some reason it ends up with $primary as bg color
-$nav-tabs-link-active-bg: #fff;
-$nav-tabs-link-active-color: $gray-700;
-
-// pagination tweaks
-$pagination-color: $white;
-$pagination-bg: $gray-500;
-$pagination-hover-color: $white;
-$pagination-hover-bg: $gray-700;
-$pagination-active-bg: $pagination-hover-bg;
-$pagination-disabled-color: $white;
-$pagination-disabled-bg: $gray-300;
-
-$progress-bg: darken($light, 10%);
-
-$with-click-default: $black;
-$with-click-dark: $white;
-$with-click-light: $black;
-
-$accordion-active-bg: $gray-100;
-$accordion-button-bg: $gray-100;
-$accordion-button-active-bg: $gray-100;
-$accordion-border-color: $gray-300;
-
-$modal-header-border-color: $gray-300;
-
-$table-bg: transparent;
-$table-accent-bg: transparent;
-
-$card-cap-bg: inherit;
-
-$kbd-color: $white;
-$kbd-bg: $dark;
-
-// Bootstrap 5.3 changed text-muted from $gray-600 to var(--bs-secondary-color)
-// which defaults to rgba($body-color, .75) - nearly black in light theme.
-// Override to match the old text-muted color.
-$body-secondary-color: $gray-600;
-
-@import "./RebootlessBootstrap";
-@import "bootswatch/dist/flatly/bootswatch";
-
-$alert-bg: $white;
-$alert-history-inactive: lighten($light, 1%);
-$alertgroup-body-bg: $white;
-$alertgroup-footer-bg: $gray-100;
-$silence-id: $dark;
-$silence-color: $dark;
-$silence-bg: lighten($gray-200, 4%);
-$silence-border: $gray-700;
-$silence-comment-color: $gray-800;
-$accordion-active-bg: $gray-200;
-$filter-input-hoover-bg: $white;
-$filter-input-hoover-color: $black;
-$placeholder-color: $secondary;
-$filterinput-border: $navbar-dark-color;
-$grid-swimlane-bg: lighten($dark, 2%);
-$bg-focused: lighten($blue, 5%);
-$annotation-link-border: $light;
-
-$components-date-range-sub-color: $black;
-
-$input-range-track-background: $gray-400;
-$input-range-thumb-font-color: $white;
-
-$color-default: #708090;
-
-@import "./BootstrapRoot.scss";
-@import "./Components";
-
-a {
- color: $link-color;
-}
-
-button.btn {
- --bs-btn-active-border-color: transparent;
- --bs-btn-hover-border-color: transparent;
-}
diff --git a/ui/src/Styles/LightTheme.tsx b/ui/src/Styles/LightTheme.tsx
deleted file mode 100644
index d5e43e410..000000000
--- a/ui/src/Styles/LightTheme.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { FC } from "react";
-
-import "./LightThemeLoader.scss";
-
-const LightTheme: FC = () => null;
-
-export default LightTheme;
diff --git a/ui/src/Styles/LightThemeLoader.scss b/ui/src/Styles/LightThemeLoader.scss
deleted file mode 100644
index af9ca3aae..000000000
--- a/ui/src/Styles/LightThemeLoader.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.theme-light {
- @import "./LightTheme";
-}
diff --git a/ui/src/Styles/RebootlessBootstrap.scss b/ui/src/Styles/RebootlessBootstrap.scss
deleted file mode 100644
index 43cf86f93..000000000
--- a/ui/src/Styles/RebootlessBootstrap.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-// Configuration
-@import "bootstrap/scss/functions";
-@import "bootstrap/scss/variables";
-@import "bootstrap/scss/variables-dark";
-@import "bootstrap/scss/mixins";
-@import "bootstrap/scss/maps";
-@import "bootstrap/scss/utilities";
-
-// Layout & components
-//@import "bootstrap/scss/root";
-//@import "bootstrap/scss/reboot";
-//@import "bootstrap/scss/type";
-@import "bootstrap/scss/images";
-@import "bootstrap/scss/containers";
-@import "bootstrap/scss/grid";
-@import "bootstrap/scss/tables";
-@import "bootstrap/scss/forms";
-@import "bootstrap/scss/buttons";
-@import "bootstrap/scss/transitions";
-@import "bootstrap/scss/dropdown";
-@import "bootstrap/scss/button-group";
-@import "bootstrap/scss/nav";
-@import "bootstrap/scss/navbar";
-@import "bootstrap/scss/card";
-@import "bootstrap/scss/accordion";
-@import "bootstrap/scss/breadcrumb";
-@import "bootstrap/scss/pagination";
-@import "bootstrap/scss/badge";
-@import "bootstrap/scss/alert";
-@import "bootstrap/scss/progress";
-@import "bootstrap/scss/list-group";
-@import "bootstrap/scss/close";
-@import "bootstrap/scss/toasts";
-@import "bootstrap/scss/modal";
-@import "bootstrap/scss/tooltip";
-@import "bootstrap/scss/popover";
-@import "bootstrap/scss/carousel";
-@import "bootstrap/scss/spinners";
-@import "bootstrap/scss/offcanvas";
-@import "bootstrap/scss/placeholders";
-
-// Helpers
-@import "bootstrap/scss/helpers";
-
-// Utilities
-@import "bootstrap/scss/utilities/api";
diff --git a/ui/src/Styles/ResetCSS.scss b/ui/src/Styles/ResetCSS.scss
deleted file mode 100644
index 7729780a8..000000000
--- a/ui/src/Styles/ResetCSS.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-@import "./Fonts";
-
-$font-size-base: 1rem;
-$body-bg: #455a64;
-
-@import "bootstrap/scss/functions";
-@import "bootswatch/dist/flatly/variables";
-@import "bootstrap/scss/variables";
-@import "bootstrap/scss/variables-dark";
-@import "bootstrap/scss/mixins";
-@import "bootstrap/scss/maps";
-@import "bootstrap/scss/root";
-@import "bootstrap/scss/type";
-@import "bootstrap/scss/reboot";
diff --git a/ui/src/Styles/Theme.scss b/ui/src/Styles/Theme.scss
new file mode 100644
index 000000000..fcae03dcf
--- /dev/null
+++ b/ui/src/Styles/Theme.scss
@@ -0,0 +1,509 @@
+@use "bootswatch/dist/flatly/variables" as flatly;
+@use "bootswatch/dist/darkly/variables" as darkly;
+
+$lead-font-weight: 400;
+
+// custom "dark" color, little less dark than flatly
+$blue: #455a64;
+// default is ~0.97rem
+$font-size-base: 1rem;
+
+// make dark darker, default it's $gray-700
+$dark: #3b4247;
+
+$enable-shadows: true;
+$enable-dark-mode: false;
+
+$btn-box-shadow: 0;
+$btn-focus-box-shadow: 0;
+$btn-active-box-shadow: 0;
+
+$tooltip-max-width: 400px;
+
+$body-bg: #455a64;
+
+@import "./Fonts";
+
+@import "bootstrap/scss/functions";
+
+// Import flatly (light) variables as base
+@import "bootswatch/dist/flatly/variables";
+
+// make links light gray by default instead of green
+$link-color: $gray-700;
+
+$navbar-dark-brand-color: $navbar-dark-color;
+$navbar-dark-brand-hover-color: $gray-200;
+$navbar-dark-hover-color: $gray-200;
+$navbar-dark-active-color: $gray-200;
+
+// fix active tab color, for some reason it ends up with $primary as bg color
+$nav-tabs-link-active-bg: #fff;
+$nav-tabs-link-active-color: $gray-700;
+
+// pagination tweaks
+$pagination-color: $white;
+$pagination-bg: $gray-500;
+$pagination-hover-color: $white;
+$pagination-hover-bg: $gray-700;
+$pagination-active-bg: $pagination-hover-bg;
+$pagination-disabled-color: $white;
+$pagination-disabled-bg: $gray-300;
+
+$progress-bg: darken($light, 10%);
+
+$accordion-active-bg: $gray-100;
+$accordion-button-bg: $gray-100;
+$accordion-button-active-bg: $gray-100;
+$accordion-border-color: $gray-300;
+
+$modal-header-border-color: $gray-300;
+
+$table-bg: transparent;
+$table-accent-bg: transparent;
+
+$card-cap-bg: inherit;
+
+$kbd-color: $white;
+$kbd-bg: $dark;
+
+// Bootstrap 5.3 changed text-muted from $gray-600 to var(--bs-secondary-color)
+// which defaults to rgba($body-color, .75) - nearly black in light theme.
+// Override to match the old text-muted color.
+$body-secondary-color: $gray-600;
+
+// Import Bootstrap variables with !default (won't override flatly values already set)
+@import "bootstrap/scss/variables";
+@import "bootstrap/scss/variables-dark";
+@import "bootstrap/scss/mixins";
+@import "bootstrap/scss/maps";
+@import "bootstrap/scss/utilities";
+
+// Bootstrap layout & components
+@import "bootstrap/scss/root";
+@import "bootstrap/scss/reboot";
+@import "bootstrap/scss/type";
+@import "bootstrap/scss/images";
+@import "bootstrap/scss/containers";
+@import "bootstrap/scss/grid";
+@import "bootstrap/scss/tables";
+@import "bootstrap/scss/forms";
+@import "bootstrap/scss/buttons";
+@import "bootstrap/scss/transitions";
+@import "bootstrap/scss/dropdown";
+@import "bootstrap/scss/button-group";
+@import "bootstrap/scss/nav";
+@import "bootstrap/scss/navbar";
+@import "bootstrap/scss/card";
+@import "bootstrap/scss/accordion";
+@import "bootstrap/scss/breadcrumb";
+@import "bootstrap/scss/pagination";
+@import "bootstrap/scss/badge";
+@import "bootstrap/scss/alert";
+@import "bootstrap/scss/progress";
+@import "bootstrap/scss/list-group";
+@import "bootstrap/scss/close";
+@import "bootstrap/scss/toasts";
+@import "bootstrap/scss/modal";
+@import "bootstrap/scss/tooltip";
+@import "bootstrap/scss/popover";
+@import "bootstrap/scss/carousel";
+@import "bootstrap/scss/spinners";
+@import "bootstrap/scss/offcanvas";
+@import "bootstrap/scss/placeholders";
+
+// Bootstrap helpers & utilities
+@import "bootstrap/scss/helpers";
+@import "bootstrap/scss/utilities/api";
+
+// Bootswatch flatly component overrides
+@import "bootswatch/dist/flatly/bootswatch";
+
+// Light color mode — flatly colors
+[data-bs-theme="light"] {
+ background-color: #455a64;
+ --bs-body-bg: #455a64;
+ --bs-body-bg-rgb: 69, 90, 100;
+
+ --karma-alert-bg: #{$white};
+ --karma-alert-history-inactive: #{lighten($light, 1%)};
+ --karma-alertgroup-body-bg: #{$white};
+ --karma-alertgroup-footer-bg: #{$gray-100};
+ --karma-silence-id: #{$dark};
+ --karma-silence-color: #{$dark};
+ --karma-silence-bg: #{lighten($gray-200, 4%)};
+ --karma-silence-border: #{$gray-700};
+ --karma-silence-comment-color: #{$gray-800};
+ --karma-filter-input-hoover-bg: #{$white};
+ --karma-filter-input-hoover-color: #{$black};
+ --karma-placeholder-color: #{$secondary};
+ --karma-filterinput-border: #{$navbar-dark-color};
+ --karma-grid-swimlane-bg: #{lighten($dark, 2%)};
+ --karma-bg-focused: #{lighten($blue, 5%)};
+ --karma-bg-focused-rgb: #{red(lighten($blue, 5%))}, #{green(lighten($blue, 5%))}, #{blue(lighten($blue, 5%))};
+ --karma-annotation-link-border: #{$light};
+ --karma-components-date-range-sub-color: #{$black};
+ --karma-input-range-track-background: #{$gray-400};
+ --karma-input-range-thumb-font-color: #{$white};
+ --karma-color-default: #708090;
+ --karma-with-click-default: #{$black};
+ --karma-with-click-dark: #{$white};
+ --karma-with-click-light: #{$black};
+ --karma-accordion-border-color: #{$gray-300};
+ --karma-link-color: #{$gray-700};
+ --karma-toast-bg: #{darken($dark, 5%)};
+ --karma-toast-bg-rgb: #{red(darken($dark, 5%))}, #{green(darken($dark, 5%))}, #{blue(darken($dark, 5%))};
+ --karma-progress-bg: #{darken($light, 10%)};
+ --karma-label-primary-border: #{lighten($primary, 2%)};
+ --karma-label-secondary-border: #{darken($secondary, 1%)};
+ --karma-label-secondary-bg: #{darken($secondary, 2%)};
+ --karma-label-success-border: #{darken($success, 2%)};
+ --karma-label-danger-border: #{lighten($danger, 2%)};
+ --karma-label-warning-border: #{lighten($warning, 3%)};
+ --karma-label-info-border: #{darken($info, 2%)};
+ --karma-label-dark-border: #{darken($dark, 2%)};
+
+ .modal {
+ --bs-modal-bg: #{$white};
+ }
+
+ .accordion {
+ --bs-accordion-bg: #{$white};
+ }
+
+ .list-group {
+ --bs-list-group-bg: #{$white};
+ }
+
+ .card {
+ --bs-card-bg: #{$white};
+ }
+
+ .popover {
+ --bs-popover-bg: #{$white};
+ }
+
+ .offcanvas {
+ --bs-offcanvas-bg: #{$white};
+ }
+
+ .form-control {
+ background-color: #{$white};
+ }
+
+ .form-select {
+ background-color: #{$white};
+ }
+
+ .form-check-input {
+ --bs-form-check-bg: #{$white};
+ }
+
+ .nav-tabs .nav-link.active {
+ color: #{$gray-900};
+ }
+
+ .dropdown-menu {
+ --bs-dropdown-bg: #{$white};
+ --bs-dropdown-link-color: #{$gray-700};
+ --bs-dropdown-link-hover-color: #{$white};
+ --bs-dropdown-link-hover-bg: #{$primary};
+ }
+}
+
+// Dark color mode — darkly colors
+[data-bs-theme="dark"] {
+ background-color: #455a64;
+ color: #{darkly.$body-color};
+ --bs-body-bg: #455a64;
+ --bs-body-bg-rgb: 69, 90, 100;
+
+ --bs-body-color: #{darkly.$body-color};
+ --bs-emphasis-color: #{darkly.$white};
+ --bs-secondary-color: #{rgba(darkly.$gray-300, 0.75)};
+ --bs-secondary-bg: #{darkly.$secondary};
+ --bs-tertiary-color: #{rgba(darkly.$gray-300, 0.5)};
+ --bs-tertiary-bg: #{darken(darkly.$gray-800, 2%)};
+ --bs-primary: #455a64;
+ --bs-secondary: #{darkly.$secondary};
+ --bs-success: #{darkly.$success};
+ --bs-info: #{darkly.$info};
+ --bs-warning: #{darkly.$warning};
+ --bs-danger: #{darkly.$danger};
+ --bs-light: #{lighten(darkly.$gray-800, 5%)};
+ --bs-dark: #{darken(darkly.$dark, 4%)};
+ --bs-primary-rgb: 69, 90, 100;
+ --bs-secondary-rgb: #{red(darkly.$secondary)}, #{green(darkly.$secondary)}, #{blue(darkly.$secondary)};
+ --bs-success-rgb: #{red(darkly.$success)}, #{green(darkly.$success)}, #{blue(darkly.$success)};
+ --bs-info-rgb: #{red(darkly.$info)}, #{green(darkly.$info)}, #{blue(darkly.$info)};
+ --bs-warning-rgb: #{red(darkly.$warning)}, #{green(darkly.$warning)}, #{blue(darkly.$warning)};
+ --bs-danger-rgb: #{red(darkly.$danger)}, #{green(darkly.$danger)}, #{blue(darkly.$danger)};
+ --bs-light-rgb: #{red(lighten(darkly.$gray-800, 5%))}, #{green(lighten(darkly.$gray-800, 5%))}, #{blue(lighten(darkly.$gray-800, 5%))};
+ --bs-dark-rgb: #{red(darken(darkly.$dark, 4%))}, #{green(darken(darkly.$dark, 4%))}, #{blue(darken(darkly.$dark, 4%))};
+ --bs-link-color: #{darkly.$gray-400};
+ --bs-link-hover-color: #{lighten(darkly.$gray-400, 10%)};
+ --bs-border-color: #{darkly.$secondary};
+
+ --karma-alert-bg: #{darkly.$gray-800};
+ --karma-alert-history-inactive: #{lighten(darkly.$gray-700, 2%)};
+ --karma-alertgroup-body-bg: #{lighten(darkly.$gray-700, 5%)};
+ --karma-alertgroup-footer-bg: #{lighten(darkly.$gray-700, 2%)};
+ --karma-silence-id: #{darkly.$white};
+ --karma-silence-color: #{darkly.$white};
+ --karma-silence-bg: #{lighten(darkly.$gray-900, 4%)};
+ --karma-silence-border: #{darkly.$black};
+ --karma-silence-comment-color: #{darkly.$gray-500};
+ --karma-filter-input-hoover-bg: #{darkly.$gray-700};
+ --karma-filter-input-hoover-color: #{darkly.$white};
+ --karma-placeholder-color: #{darkly.$gray-600};
+ --karma-filterinput-border: #{darkly.$navbar-dark-color};
+ --karma-grid-swimlane-bg: #{lighten(darken(darkly.$dark, 4%), 2%)};
+ --karma-bg-focused: #{darken(#455a64, 5%)};
+ --karma-bg-focused-rgb: #{red(darken(#455a64, 5%))}, #{green(darken(#455a64, 5%))}, #{blue(darken(#455a64, 5%))};
+ --karma-annotation-link-border: #{darkly.$secondary};
+ --karma-components-date-range-sub-color: #{darkly.$white};
+ --karma-input-range-track-background: #{darkly.$secondary};
+ --karma-input-range-thumb-font-color: #{darkly.$white};
+ --karma-color-default: #708090;
+ --karma-with-click-default: #{darkly.$white};
+ --karma-with-click-dark: #{darkly.$white};
+ --karma-with-click-light: #{darkly.$dark};
+ --karma-accordion-border-color: #{lighten(darkly.$gray-700, 5%)};
+ --karma-link-color: #{darkly.$gray-400};
+ --karma-toast-bg: #{darken(darken(darkly.$dark, 4%), 5%)};
+ --karma-toast-bg-rgb: #{red(darken(darken(darkly.$dark, 4%), 5%))}, #{green(darken(darken(darkly.$dark, 4%), 5%))}, #{blue(darken(darken(darkly.$dark, 4%), 5%))};
+ --karma-progress-bg: #{darkly.$black};
+ --karma-label-primary-border: #{lighten(darkly.$primary, 2%)};
+ --karma-label-secondary-border: #{darken(darkly.$secondary, 1%)};
+ --karma-label-secondary-bg: #{darken(darkly.$secondary, 2%)};
+ --karma-label-success-border: #{darken(darkly.$success, 2%)};
+ --karma-label-danger-border: #{lighten(darkly.$danger, 2%)};
+ --karma-label-warning-border: #{lighten(darkly.$warning, 3%)};
+ --karma-label-info-border: #{darken(darkly.$info, 2%)};
+ --karma-label-dark-border: #{darken(darkly.$dark, 2%)};
+
+ // Component overrides for dark theme
+ .badge,
+ .modal-content {
+ color: #{darkly.$white};
+ }
+
+ .navbar {
+ @supports (backdrop-filter: blur(12px)) {
+ background-color: rgba(#455a64, 0.85);
+ }
+ @supports not (backdrop-filter: blur(12px)) {
+ background-color: rgba(#455a64, 0.95);
+ }
+ }
+
+ .nav-tabs {
+ --bs-nav-tabs-border-color: #{darkly.$gray-700};
+ --bs-nav-tabs-link-hover-border-color: #{darkly.$gray-700} #{darkly.$gray-700} transparent;
+
+ .nav-link.active {
+ color: #{darkly.$white};
+ background-color: #{darkly.$gray-800};
+ border-color: #{darkly.$gray-700} #{darkly.$gray-700} #{darkly.$gray-800};
+ }
+ }
+
+ .form-control {
+ color: #{darkly.$white};
+ background-color: #{darkly.$secondary};
+ border-color: #{darkly.$secondary};
+
+ &:disabled {
+ background-color: #{darkly.$gray-800};
+ }
+ }
+
+ .form-check-input {
+ background-color: #{darkly.$gray-100};
+ border-color: #{darkly.$gray-100};
+
+ &:checked {
+ background-color: #455a64;
+ border-color: #455a64;
+ }
+
+ &:disabled {
+ background-color: #{darkly.$gray-700};
+
+ &:checked {
+ background-color: #{darkly.$gray-700};
+ }
+ }
+ }
+
+ .form-select {
+ color: #{darkly.$white};
+ background-color: #{darkly.$secondary};
+ border-color: #{darkly.$secondary};
+ }
+
+ .input-group-text {
+ background-color: #{darkly.$gray-800};
+ }
+
+ .dropdown-menu {
+ --bs-dropdown-bg: #{darken(darkly.$gray-800, 2%)};
+ --bs-dropdown-border-color: #{darkly.$gray-700};
+ --bs-dropdown-divider-bg: #{darkly.$gray-700};
+ --bs-dropdown-link-color: #{darkly.$white};
+ --bs-dropdown-link-hover-color: #{darkly.$white};
+ --bs-dropdown-link-hover-bg: #455a64;
+ }
+
+ button.btn {
+ --bs-btn-active-border-color: transparent;
+ --bs-btn-hover-border-color: transparent;
+ }
+
+ .btn-secondary {
+ --bs-btn-bg: #{darkly.$secondary};
+ --bs-btn-border-color: #{darkly.$secondary};
+ --bs-btn-hover-bg: #{lighten(darkly.$secondary, 5%)};
+ --bs-btn-hover-border-color: #{lighten(darkly.$secondary, 5%)};
+ --bs-btn-active-bg: #{lighten(darkly.$secondary, 8%)};
+ --bs-btn-active-border-color: #{lighten(darkly.$secondary, 8%)};
+ --bs-btn-disabled-bg: #{darkly.$secondary};
+ --bs-btn-disabled-border-color: #{darkly.$secondary};
+ }
+
+ .btn-light {
+ --bs-btn-bg: #{darkly.$gray-900};
+ --bs-btn-border-color: #{darkly.$gray-700};
+ --bs-btn-color: #{darkly.$white};
+ --bs-btn-hover-bg: #{darkly.$gray-700};
+ --bs-btn-hover-border-color: #{darkly.$gray-700};
+ --bs-btn-hover-color: #{darkly.$white};
+ --bs-btn-active-bg: #{darkly.$gray-800};
+ --bs-btn-active-border-color: #{darkly.$gray-700};
+ --bs-btn-active-color: #{darkly.$white};
+ --bs-btn-disabled-bg: #{darkly.$gray-900};
+ --bs-btn-disabled-border-color: #{darkly.$gray-700};
+ --bs-btn-disabled-color: #{darkly.$gray-600};
+ }
+
+ .btn-outline-secondary {
+ --bs-btn-color: #{darkly.$secondary};
+ --bs-btn-border-color: #{darkly.$secondary};
+ --bs-btn-hover-color: #{darkly.$white};
+ --bs-btn-hover-bg: #{darkly.$secondary};
+ --bs-btn-hover-border-color: #{darkly.$secondary};
+ --bs-btn-active-color: #{darkly.$white};
+ --bs-btn-active-bg: #{darkly.$secondary};
+ --bs-btn-active-border-color: #{darkly.$secondary};
+ --bs-btn-disabled-color: #{darkly.$secondary};
+ --bs-btn-disabled-border-color: #{darkly.$secondary};
+ }
+
+ .accordion {
+ --bs-accordion-bg: #{darkly.$gray-800};
+ --bs-accordion-btn-bg: #{darkly.$gray-700};
+ --bs-accordion-active-bg: #{darkly.$gray-700};
+ --bs-accordion-border-color: #{lighten(darkly.$gray-700, 5%)};
+ --bs-accordion-btn-color: #{darkly.$white};
+ }
+
+ .accordion-button::after {
+ filter: invert(1) grayscale(100%) brightness(200%);
+ }
+
+ .list-group {
+ --bs-list-group-bg: #{darkly.$list-group-bg};
+ --bs-list-group-border-color: #{darkly.$list-group-border-color};
+ --bs-list-group-color: #{darkly.$body-color};
+ }
+
+ .card {
+ --bs-card-bg: #{darkly.$card-bg};
+ --bs-card-cap-bg: inherit;
+ --bs-card-color: #{darkly.$body-color};
+ }
+
+ .modal-content {
+ --bs-modal-bg: #{darkly.$modal-content-bg};
+ --bs-modal-border-color: #{darkly.$modal-content-border-color};
+ --bs-modal-header-border-color: #{darkly.$modal-header-border-color};
+ --bs-modal-footer-border-color: #{darkly.$modal-header-border-color};
+ }
+
+ .btn-close {
+ // TODO: get rid of _bootswatch.scss imports and then we can simply set color here.
+ filter: invert(1) grayscale(100%) brightness(200%);
+ }
+
+ .progress {
+ --bs-progress-bg: #{darkly.$progress-bg};
+ }
+
+ .pagination {
+ --bs-pagination-color: #{darkly.$white};
+ --bs-pagination-bg: #{darkly.$gray-700};
+ --bs-pagination-hover-color: #{darkly.$white};
+ --bs-pagination-hover-bg: #455a64;
+ --bs-pagination-active-bg: #455a64;
+ --bs-pagination-border-color: #{darken(darkly.$dark, 4%)};
+ --bs-pagination-disabled-color: #{darkly.$gray-600};
+ --bs-pagination-disabled-bg: #{darkly.$gray-700};
+ }
+
+ .toast {
+ --bs-toast-bg: #{darkly.$toast-background-color};
+ --bs-toast-header-bg: #{darkly.$toast-header-background-color};
+ }
+
+ .popover {
+ --bs-popover-bg: #{darkly.$popover-bg};
+ --bs-popover-header-bg: #{darkly.$popover-header-bg};
+ }
+
+ .tooltip {
+ --bs-tooltip-bg: var(--bs-tertiary-bg);
+ --bs-tooltip-color: var(--bs-emphasis-color);
+ }
+
+ // darkly bootswatch alert override
+ .alert {
+ color: #{darkly.$white};
+ border: none;
+
+ a,
+ .alert-link {
+ color: #{darkly.$white};
+ text-decoration: underline;
+ }
+
+ @each $color, $value in (
+ "primary": darkly.$primary,
+ "secondary": darkly.$secondary,
+ "success": darkly.$success,
+ "info": darkly.$info,
+ "warning": darkly.$warning,
+ "danger": darkly.$danger,
+ "light": darkly.$light,
+ "dark": darkly.$dark,
+ ) {
+ &-#{$color} {
+ background-color: #{$value};
+ }
+ }
+ }
+
+ .breadcrumb a {
+ color: #{darkly.$white};
+ }
+}
+
+@import "./Components";
+
+a {
+ color: var(--karma-link-color);
+}
+
+button.btn {
+ --bs-btn-active-border-color: transparent;
+ --bs-btn-hover-border-color: transparent;
+}
diff --git a/ui/src/Styles/index.test.tsx b/ui/src/Styles/index.test.tsx
deleted file mode 100644
index 6264a50e7..000000000
--- a/ui/src/Styles/index.test.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { render } from "@testing-library/react";
-
-import LightTheme from "./LightTheme";
-import DarkTheme from "./DarkTheme";
-
-describe("", () => {
- it("renders null", () => {
- const { container } = render();
- expect(container.innerHTML).toBe("");
- });
-});
-
-describe("", () => {
- it("renders null", () => {
- const { container } = render();
- expect(container.innerHTML).toBe("");
- });
-});
diff --git a/ui/src/e2e/snapshots/chromium/Grid.png b/ui/src/e2e/snapshots/chromium/Grid.png
index 1c32f430c..856c9e9e3 100644
Binary files a/ui/src/e2e/snapshots/chromium/Grid.png and b/ui/src/e2e/snapshots/chromium/Grid.png differ
diff --git a/ui/src/e2e/snapshots/chromium/GridColorTitleBar.png b/ui/src/e2e/snapshots/chromium/GridColorTitleBar.png
index 8d471cede..f61adc1ce 100644
Binary files a/ui/src/e2e/snapshots/chromium/GridColorTitleBar.png and b/ui/src/e2e/snapshots/chromium/GridColorTitleBar.png differ
diff --git a/ui/src/e2e/snapshots/chromium/InternalError.png b/ui/src/e2e/snapshots/chromium/InternalError.png
index c16211c7b..cb4615898 100644
Binary files a/ui/src/e2e/snapshots/chromium/InternalError.png and b/ui/src/e2e/snapshots/chromium/InternalError.png differ
diff --git a/ui/src/e2e/snapshots/chromium/MainModal.png b/ui/src/e2e/snapshots/chromium/MainModal.png
index 6aadf14f6..af0d3021f 100644
Binary files a/ui/src/e2e/snapshots/chromium/MainModal.png and b/ui/src/e2e/snapshots/chromium/MainModal.png differ
diff --git a/ui/src/e2e/snapshots/chromium/ManagedSilence.png b/ui/src/e2e/snapshots/chromium/ManagedSilence.png
index da891c7f2..7a13bb0a3 100644
Binary files a/ui/src/e2e/snapshots/chromium/ManagedSilence.png and b/ui/src/e2e/snapshots/chromium/ManagedSilence.png differ
diff --git a/ui/src/e2e/snapshots/chromium/NavBar.png b/ui/src/e2e/snapshots/chromium/NavBar.png
index d23d5d077..0fff47865 100644
Binary files a/ui/src/e2e/snapshots/chromium/NavBar.png and b/ui/src/e2e/snapshots/chromium/NavBar.png differ
diff --git a/ui/src/e2e/snapshots/chromium/NavBarPaused.png b/ui/src/e2e/snapshots/chromium/NavBarPaused.png
index 252b66f77..e292c685d 100644
Binary files a/ui/src/e2e/snapshots/chromium/NavBarPaused.png and b/ui/src/e2e/snapshots/chromium/NavBarPaused.png differ
diff --git a/ui/src/e2e/snapshots/chromium/SilenceModalBrowser.png b/ui/src/e2e/snapshots/chromium/SilenceModalBrowser.png
index b754eed25..736a78544 100644
Binary files a/ui/src/e2e/snapshots/chromium/SilenceModalBrowser.png and b/ui/src/e2e/snapshots/chromium/SilenceModalBrowser.png differ
diff --git a/ui/src/e2e/snapshots/chromium/SilenceModalEditor.png b/ui/src/e2e/snapshots/chromium/SilenceModalEditor.png
index 3437194f6..3d6f631da 100644
Binary files a/ui/src/e2e/snapshots/chromium/SilenceModalEditor.png and b/ui/src/e2e/snapshots/chromium/SilenceModalEditor.png differ
diff --git a/ui/src/e2e/snapshots/chromium/SilenceModalEditorEndsTab.png b/ui/src/e2e/snapshots/chromium/SilenceModalEditorEndsTab.png
new file mode 100644
index 000000000..8e7ae7c73
Binary files /dev/null and b/ui/src/e2e/snapshots/chromium/SilenceModalEditorEndsTab.png differ
diff --git a/ui/src/e2e/snapshots/chromium/UpgradeNeeded.png b/ui/src/e2e/snapshots/chromium/UpgradeNeeded.png
index 16dea0d7d..028ad1bf6 100644
Binary files a/ui/src/e2e/snapshots/chromium/UpgradeNeeded.png and b/ui/src/e2e/snapshots/chromium/UpgradeNeeded.png differ
diff --git a/ui/src/e2e/snapshots/firefox/Grid.png b/ui/src/e2e/snapshots/firefox/Grid.png
index 9e2f9835a..a92b1b572 100644
Binary files a/ui/src/e2e/snapshots/firefox/Grid.png and b/ui/src/e2e/snapshots/firefox/Grid.png differ
diff --git a/ui/src/e2e/snapshots/firefox/GridColorTitleBar.png b/ui/src/e2e/snapshots/firefox/GridColorTitleBar.png
index de66109d8..382d45b08 100644
Binary files a/ui/src/e2e/snapshots/firefox/GridColorTitleBar.png and b/ui/src/e2e/snapshots/firefox/GridColorTitleBar.png differ
diff --git a/ui/src/e2e/snapshots/firefox/InternalError.png b/ui/src/e2e/snapshots/firefox/InternalError.png
index d1eefcef2..6a6c72113 100644
Binary files a/ui/src/e2e/snapshots/firefox/InternalError.png and b/ui/src/e2e/snapshots/firefox/InternalError.png differ
diff --git a/ui/src/e2e/snapshots/firefox/MainModal.png b/ui/src/e2e/snapshots/firefox/MainModal.png
index 36a7bed7f..734a34c59 100644
Binary files a/ui/src/e2e/snapshots/firefox/MainModal.png and b/ui/src/e2e/snapshots/firefox/MainModal.png differ
diff --git a/ui/src/e2e/snapshots/firefox/ManagedSilence.png b/ui/src/e2e/snapshots/firefox/ManagedSilence.png
index c81fb8481..a1a51898b 100644
Binary files a/ui/src/e2e/snapshots/firefox/ManagedSilence.png and b/ui/src/e2e/snapshots/firefox/ManagedSilence.png differ
diff --git a/ui/src/e2e/snapshots/firefox/NavBar.png b/ui/src/e2e/snapshots/firefox/NavBar.png
index a2e2614f8..7fde1a8d7 100644
Binary files a/ui/src/e2e/snapshots/firefox/NavBar.png and b/ui/src/e2e/snapshots/firefox/NavBar.png differ
diff --git a/ui/src/e2e/snapshots/firefox/NavBarPaused.png b/ui/src/e2e/snapshots/firefox/NavBarPaused.png
index f1db2d7d3..b5ccd7123 100644
Binary files a/ui/src/e2e/snapshots/firefox/NavBarPaused.png and b/ui/src/e2e/snapshots/firefox/NavBarPaused.png differ
diff --git a/ui/src/e2e/snapshots/firefox/SilenceModalBrowser.png b/ui/src/e2e/snapshots/firefox/SilenceModalBrowser.png
index 58d3415d9..e1179ceb1 100644
Binary files a/ui/src/e2e/snapshots/firefox/SilenceModalBrowser.png and b/ui/src/e2e/snapshots/firefox/SilenceModalBrowser.png differ
diff --git a/ui/src/e2e/snapshots/firefox/SilenceModalEditor.png b/ui/src/e2e/snapshots/firefox/SilenceModalEditor.png
index 91b5b51f9..b04ccc733 100644
Binary files a/ui/src/e2e/snapshots/firefox/SilenceModalEditor.png and b/ui/src/e2e/snapshots/firefox/SilenceModalEditor.png differ
diff --git a/ui/src/e2e/snapshots/firefox/SilenceModalEditorEndsTab.png b/ui/src/e2e/snapshots/firefox/SilenceModalEditorEndsTab.png
new file mode 100644
index 000000000..69a692c42
Binary files /dev/null and b/ui/src/e2e/snapshots/firefox/SilenceModalEditorEndsTab.png differ
diff --git a/ui/src/e2e/snapshots/firefox/UpgradeNeeded.png b/ui/src/e2e/snapshots/firefox/UpgradeNeeded.png
index 58ba4d746..08f5950ff 100644
Binary files a/ui/src/e2e/snapshots/firefox/UpgradeNeeded.png and b/ui/src/e2e/snapshots/firefox/UpgradeNeeded.png differ
diff --git a/ui/src/e2e/snapshots/webkit/Grid.png b/ui/src/e2e/snapshots/webkit/Grid.png
index 5c7c8cc76..9ac1fbeb1 100644
Binary files a/ui/src/e2e/snapshots/webkit/Grid.png and b/ui/src/e2e/snapshots/webkit/Grid.png differ
diff --git a/ui/src/e2e/snapshots/webkit/GridColorTitleBar.png b/ui/src/e2e/snapshots/webkit/GridColorTitleBar.png
index 4676cebb4..baf14f66b 100644
Binary files a/ui/src/e2e/snapshots/webkit/GridColorTitleBar.png and b/ui/src/e2e/snapshots/webkit/GridColorTitleBar.png differ
diff --git a/ui/src/e2e/snapshots/webkit/InternalError.png b/ui/src/e2e/snapshots/webkit/InternalError.png
index c3cf30cd5..5c62d6257 100644
Binary files a/ui/src/e2e/snapshots/webkit/InternalError.png and b/ui/src/e2e/snapshots/webkit/InternalError.png differ
diff --git a/ui/src/e2e/snapshots/webkit/MainModal.png b/ui/src/e2e/snapshots/webkit/MainModal.png
index c7e58302c..c3b3a7f8f 100644
Binary files a/ui/src/e2e/snapshots/webkit/MainModal.png and b/ui/src/e2e/snapshots/webkit/MainModal.png differ
diff --git a/ui/src/e2e/snapshots/webkit/ManagedSilence.png b/ui/src/e2e/snapshots/webkit/ManagedSilence.png
index 7edd53806..b0b7988c5 100644
Binary files a/ui/src/e2e/snapshots/webkit/ManagedSilence.png and b/ui/src/e2e/snapshots/webkit/ManagedSilence.png differ
diff --git a/ui/src/e2e/snapshots/webkit/NavBar.png b/ui/src/e2e/snapshots/webkit/NavBar.png
index a8b3674b7..2fa44b395 100644
Binary files a/ui/src/e2e/snapshots/webkit/NavBar.png and b/ui/src/e2e/snapshots/webkit/NavBar.png differ
diff --git a/ui/src/e2e/snapshots/webkit/NavBarPaused.png b/ui/src/e2e/snapshots/webkit/NavBarPaused.png
index 201035fe0..0c003bd3a 100644
Binary files a/ui/src/e2e/snapshots/webkit/NavBarPaused.png and b/ui/src/e2e/snapshots/webkit/NavBarPaused.png differ
diff --git a/ui/src/e2e/snapshots/webkit/SilenceModalBrowser.png b/ui/src/e2e/snapshots/webkit/SilenceModalBrowser.png
index 062a8ace7..ec08582c8 100644
Binary files a/ui/src/e2e/snapshots/webkit/SilenceModalBrowser.png and b/ui/src/e2e/snapshots/webkit/SilenceModalBrowser.png differ
diff --git a/ui/src/e2e/snapshots/webkit/SilenceModalEditor.png b/ui/src/e2e/snapshots/webkit/SilenceModalEditor.png
index 146795648..51917af98 100644
Binary files a/ui/src/e2e/snapshots/webkit/SilenceModalEditor.png and b/ui/src/e2e/snapshots/webkit/SilenceModalEditor.png differ
diff --git a/ui/src/e2e/snapshots/webkit/SilenceModalEditorEndsTab.png b/ui/src/e2e/snapshots/webkit/SilenceModalEditorEndsTab.png
new file mode 100644
index 000000000..8827ade3d
Binary files /dev/null and b/ui/src/e2e/snapshots/webkit/SilenceModalEditorEndsTab.png differ
diff --git a/ui/src/e2e/snapshots/webkit/SilenceModalEmptyBrowser.png b/ui/src/e2e/snapshots/webkit/SilenceModalEmptyBrowser.png
index 731e79268..5fa598062 100644
Binary files a/ui/src/e2e/snapshots/webkit/SilenceModalEmptyBrowser.png and b/ui/src/e2e/snapshots/webkit/SilenceModalEmptyBrowser.png differ
diff --git a/ui/src/e2e/snapshots/webkit/UpgradeNeeded.png b/ui/src/e2e/snapshots/webkit/UpgradeNeeded.png
index d6713d93c..ae362ad17 100644
Binary files a/ui/src/e2e/snapshots/webkit/UpgradeNeeded.png and b/ui/src/e2e/snapshots/webkit/UpgradeNeeded.png differ
diff --git a/ui/src/e2e/stories.tsx b/ui/src/e2e/stories.tsx
index 86e055cd4..d5f29ba69 100644
--- a/ui/src/e2e/stories.tsx
+++ b/ui/src/e2e/stories.tsx
@@ -1,7 +1,6 @@
import React from "react";
import { createRoot } from "react-dom/client";
-import { addHours } from "date-fns/addHours";
import { addDays } from "date-fns/addDays";
import { faArrowUp } from "@fortawesome/free-solid-svg-icons/faArrowUp";
@@ -39,7 +38,7 @@ import {
UpgradeToastMessage,
} from "Components/Toast/ToastMessages";
-import "Styles/Percy.scss";
+import "Styles/E2E.scss";
const jsonResponse = (data: unknown): Response =>
new Response(JSON.stringify(data), {
@@ -440,7 +439,7 @@ const managedSilenceStory = (): React.ReactNode => {
return (
-
+
{
silenceFormStore.data.setAuthor("me@example.com");
silenceFormStore.data.setComment("This is a test silence");
- silenceFormStore.data.setStart(new Date("2018-08-14T17:36:40"));
- silenceFormStore.data.setEnd(
- addDays(addHours(new Date("2018-08-14T17:36:40"), 2), 10),
- );
+ silenceFormStore.data.setStart(new Date("2018-08-14T17:36:40Z"));
+ silenceFormStore.data.setEnd(addDays(new Date("2018-08-14T19:00:00Z"), 5));
silenceFormStore.tab.setTab("editor");
return (
@@ -642,7 +639,7 @@ const darkTheme: ThemeCtx = {
const StoryRenderer = ({ storyFn }: { storyFn: () => React.ReactNode }) => (
-
+
{storyFn()}
@@ -656,7 +653,7 @@ const StoryRenderer = ({ storyFn }: { storyFn: () => React.ReactNode }) => (
marginBottom: "4px",
}}
/>
-
+
{storyFn()}
diff --git a/ui/src/e2e/visual.spec.ts b/ui/src/e2e/visual.spec.ts
index 5bcf07eec..9160fb5f6 100644
--- a/ui/src/e2e/visual.spec.ts
+++ b/ui/src/e2e/visual.spec.ts
@@ -31,3 +31,27 @@ for (const story of stories) {
});
});
}
+
+test("SilenceModalEditorEndsTab", async ({ page }) => {
+ await page.clock.install({ time: new Date("2018-08-14T17:00:00Z") });
+ await page.goto(`/src/e2e/stories.html#SilenceModalEditor`);
+ await page.locator(".modal-content").first().waitFor({ timeout: 10000 });
+ // click "Ends" tab in both light and dark theme sections
+ const endsTabs = page.locator("text=Ends");
+ for (const tab of await endsTabs.all()) {
+ await tab.click();
+ }
+ // click day 20 on each calendar to create a visible multi-day range
+ const dayButtons = page.locator(
+ ".rdp-day:not(.rdp-disabled) .rdp-day_button",
+ );
+ for (const btn of await dayButtons.all()) {
+ const text = await btn.textContent();
+ if (text?.trim() === "20") {
+ await btn.click();
+ }
+ }
+ await expect(page).toHaveScreenshot("SilenceModalEditorEndsTab.png", {
+ fullPage: true,
+ });
+});