browsertrix/frontend/src/theme.stylesheet.css
Emma Segal-Grossman 5915c24c18
Add "cancellation scheduled" state to superadmin org list (#2594)
Fixes https://github.com/webrecorder/browsertrix/issues/2595

## Changes

Adds "Subscription Cancellation Scheduled" state/icon/tooltip to
superadmin org list, with future cancellation duration/date.

Adds more subscription-related info and features to the action menu in
the same org list
- "Open in Stripe" action is visible if subscription id is a Stripe
object id
- "Plan ID" and "Action on Cancel" correspond to `planId` and
`readOnlyOnCancel` properties on `subscription` object
- There's also some additional highlighting for possible errors
(hopefully only visible on dev) — see the last screenshot for an example

Adds first pass at filters for superadmin org list
- The filters' counts update when searching
- I took an initial pass at figuring out which filters would be most
useful — we can always go back and tweak them later
2025-05-06 18:59:29 -07:00

477 lines
13 KiB
CSS

/**
* Shoelace CSS theming variables and component overrides
* https://github.com/shoelace-style/shoelace/blob/next/src/themes/light.css
*
* To make new variables available to Tailwind, update
* `theme` in tailwind.config.js
*/
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
/* Custom contextual variables */
--primary: theme(colors.primary.DEFAULT);
--success: var(--sl-color-success-600);
--warning: var(--sl-color-warning-600);
--danger: var(--sl-color-danger-600);
/* Custom font variables */
--font-monostyle-family: var(--sl-font-mono);
--font-monostyle-variation: "MONO" 0.51, "CASL" 0, "slnt" 0, "CRSV" 0;
--font-monospace-variation: "MONO" 1, "CASL" 0, "slnt" 0, "CRSV" 0;
--font-size-base: 1rem;
/* Custom screen widths */
--btrix-screen-desktop: 82.5rem; /* Should match tailwind.config.screens.desktop */
/*
* Shoelace Theme Tokens
*/
/* Primary */
--sl-color-primary-50: theme(colors.primary.50);
--sl-color-primary-100: theme(colors.primary.100);
--sl-color-primary-200: theme(colors.primary.200);
--sl-color-primary-300: theme(colors.primary.300);
--sl-color-primary-400: theme(colors.primary.400);
--sl-color-primary-500: theme(colors.primary.500);
--sl-color-primary-600: theme(colors.primary.600);
--sl-color-primary-700: theme(colors.primary.700);
--sl-color-primary-800: theme(colors.primary.800);
--sl-color-primary-900: theme(colors.primary.900);
--sl-color-primary-950: theme(colors.primary.900);
/*
* Typography
*/
/* Fonts */
--sl-font-mono: "Recursive var", SFMono-Regular, Consolas, "Liberation Mono",
Menlo, monospace;
--sl-font-sans: "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol";
/* Font sizes */
--sl-font-size-medium: 0.875rem; /* 14px */
--sl-font-size-2x-large: 2rem; /* 32px */
/* Font weights */
--sl-font-weight-medium: 500;
--sl-font-weight-semibold: 600;
/*
* Forms
*/
/* Buttons */
--sl-button-font-size-small: var(--sl-font-size-small);
--sl-button-font-size-medium: var(--sl-font-size-small);
--sl-button-font-size-large: var(--sl-font-size-medium);
/* Inputs */
--sl-input-height-small: 2rem; /* 32px */
--sl-input-font-size-small: var(--sl-font-size-small);
--sl-input-font-size-medium: var(--sl-font-size-small);
--sl-input-font-size-large: var(--sl-font-size-medium);
--sl-input-placeholder-color: var(--sl-color-neutral-400);
/* From GitHub Primer https://github.com/primer/primitives/blob/8b767947e35a79db17b9d7970836f03c904c8afe/data/colors/vars/global_light.ts#L47 */
/* TODO replace hardcoded color */
--sl-input-required-content-color: #9a6700;
/* Labels */
--sl-input-label-font-size-small: var(--sl-font-size-x-small);
--sl-input-label-font-size-medium: var(--sl-font-size-small);
--sl-input-label-font-size-large: var(--sl-font-size-medium);
--sl-input-label-color: var(--sl-color-neutral-800);
/* Help text */
--sl-input-help-text-font-size-medium: var(--sl-font-size-x-small);
--sl-shadow-x-small: 0px 1px 2px rgba(0, 0, 0, 0.15);
/* Transition */
--sl-transition-x-fast: 100ms;
}
body {
font-size: var(--sl-font-size-medium);
}
}
@layer components {
sl-avatar::part(base) {
transition: var(--sl-transition-x-fast) background-color;
}
sl-avatar:hover::part(base) {
background-color: var(--sl-color-primary-500);
}
/* Add more spacing between label, input and help text */
.form-label,
btrix-tag-input::part(form-control-label),
sl-input::part(form-control-label),
sl-textarea::part(form-control-label),
sl-select::part(form-control-label) {
--sl-spacing-3x-small: 0.375rem;
line-height: 1.4;
}
.form-label {
display: inline-block;
margin-bottom: var(--sl-spacing-3x-small);
}
.form-help-text,
btrix-tag-input::part(form-control-help-text),
sl-input::part(form-control-help-text),
sl-textarea::part(form-control-help-text),
sl-select::part(form-control-help-text) {
margin-top: var(--sl-spacing-x-small);
font-weight: 400;
/* Enable controlling help text text alignment from parent */
text-align: var(--help-text-align, left);
}
.form-help-text {
color: var(--sl-input-help-text-color);
font-size: var(--sl-input-help-text-font-size-medium);
}
/* Update button colors */
sl-button[variant="primary"]:not([outline])::part(base) {
background-color: theme(colors.primary.400);
}
sl-button[variant="primary"]:not([outline])::part(base):hover {
background-color: theme(colors.primary.500);
}
sl-radio-button[checked]::part(button) {
background-color: theme(colors.primary.500);
}
/* Elevate select and buttons */
sl-select::part(combobox),
sl-button:not([variant="text"])::part(base) {
box-shadow: var(--sl-shadow-x-small);
}
/* Prevent horizontal scrollbar */
sl-select::part(menu) {
overflow-x: hidden;
}
/* Decrease control spacing on small select */
sl-select[size="small"]::part(control) {
--sl-input-spacing-small: var(--sl-spacing-x-small);
line-height: 1.5;
}
/* Align left edge with prefix icon */
sl-menu sl-menu-label::part(base) {
padding-left: 25px;
}
/* Align left edge with selected item */
sl-select sl-menu-label::part(base) {
padding-left: var(--sl-spacing-medium);
}
sl-menu-label::part(base) {
font-weight: var(--sl-font-weight-medium);
}
/* Add border to menu */
sl-menu {
border: 1px solid var(--sl-panel-border-color);
}
/* Validation styles */
/**
* FIXME Use [data-user-invalid] selector once following is fixed
* https://github.com/webrecorder/browsertrix/issues/2497
*/
.invalid[data-invalid]:not([disabled])::part(base),
btrix-url-input[data-user-invalid]:not([disabled])::part(base),
sl-input[data-user-invalid]:not([disabled])::part(base),
sl-textarea[data-user-invalid]:not([disabled])::part(base) {
border-color: var(--sl-color-danger-400);
}
.invalid[data-invalid]:focus-within::part(base),
btrix-url-input[data-user-invalid]:focus-within::part(base),
sl-input[data-user-invalid]:focus-within::part(base),
sl-textarea[data-user-invalid]:focus-within::part(base) {
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-danger-100);
}
[data-user-invalid]:not([disabled])::part(form-control-label),
/* Required asterisk color */
[data-user-invalid]:not([disabled])::part(form-control-label)::after {
color: var(--sl-color-danger-700);
}
[data-user-invalid]:not([disabled])::part(form-control-help-text),
[data-user-invalid]:not([disabled]) .form-help-text {
color: var(--sl-color-danger-700);
}
/* TODO tailwind sets border-width: 0, see if this can be fixed in tw */
sl-divider {
border-top-width: var(--sl-panel-border-width);
}
/* Add more spacing between radio options */
sl-radio-group sl-radio:first-of-type {
margin-top: var(--sl-spacing-x-small);
}
sl-radio-group sl-radio:not(:first-of-type) {
margin-top: var(--sl-spacing-small);
}
/* Have button group take up whole width */
sl-radio-group:not([size="small"])::part(button-group),
sl-radio-group:not([size="small"]) sl-radio-button {
width: 100%;
min-width: min-content;
}
/* Style tooltip with white background */
sl-tooltip.invert-tooltip {
--sl-tooltip-arrow-size: 0;
--sl-tooltip-background-color: var(--sl-color-neutral-0);
--sl-tooltip-color: var(--sl-color-neutral-700);
}
sl-tooltip.invert-tooltip::part(body) {
outline: 1px solid var(--sl-panel-border-color);
box-shadow: var(--sl-shadow-large);
}
sl-tab-group {
--indicator-color: var(--sl-color-primary-500);
}
sl-tab::part(base) {
padding: var(--sl-spacing-small) var(--sl-spacing-medium);
}
sl-tab:not([active]):not(:hover)::part(base) {
color: var(--sl-color-neutral-500);
}
sl-tab:not([active]):hover::part(base) {
color: var(--sl-color-neutral-600);
}
sl-tab[active]::part(base) {
color: var(--sl-color-primary-500);
}
/* For single-input forms with submit button inline */
/* Requires form control and button to be direct children */
.inline-control-input,
.inline-control-input::part(form-control) {
display: contents;
}
.inline-control-form {
display: grid;
grid-template-areas:
"label ."
"input button"
"help-text .";
grid-template-columns: 1fr max-content;
column-gap: var(--sl-spacing-small);
}
.inline-control-input::part(form-control-label) {
grid-area: label;
}
.inline-control-input::part(form-control-input) {
grid-area: input;
}
.inline-control-input::part(form-control-help-text) {
grid-area: help-text;
}
.inline-control-button {
grid-area: button;
}
/* Inputs with "Max N characters" help text */
.with-max-help-text {
--help-text-align: right;
}
/* Wrap internal textarea input, e.g. for URL lists */
.textarea-wrap::part(textarea) {
white-space: pre;
}
/** Render label to the side of the input **/
.label-same-line::part(form-control) {
display: grid;
grid-template-columns: auto 1fr;
gap: var(--sl-spacing-x-small);
align-items: center;
}
.label-same-line::part(form-control-label) {
margin: 0;
}
.label-same-line::part(form-control-help-text) {
grid-column-start: 2;
}
/* Button group tweaks */
[data-sl-button-group__button--first][variant="primary"]:has(
+ [data-sl-button-group__button][variant="default"]
) {
/* Move primary button above secondary button in button group */
z-index: 1;
}
[data-sl-button-group__button--first][variant="primary"]
+ [data-sl-button-group__button][variant="default"]:not(:hover)::part(
base
) {
/* Ensure left border color matches primary button's right border color
so that no flash of default variant border color shows on hover */
border-left-color: var(--sl-color-primary-600);
}
}
@layer utilities {
/* Aesthetically closer to monospaced font: */
.font-monostyle {
@apply font-mono;
font-variation-settings: var(--font-monostyle-variation);
}
/* Actually monospaced font */
.font-monospace {
@apply font-mono;
font-variation-settings: var(--font-monospace-variation);
}
.truncate {
/* Fix tailwind clipping vertical */
overflow: clip visible;
/* Fix for if flex item: */
min-width: 0;
}
.offscreen {
position: absolute;
left: -100vw;
bottom: -100vh;
visibility: hidden;
width: 0;
height: 0;
overflow: hidden;
}
.scrollbar-hidden {
scrollbar-width: none;
}
.scrollbar-hidden::-webkit-scrollbar {
display: none;
}
.fade-out-r {
mask-image: linear-gradient(
to right,
var(--sl-panel-background-color) calc(100% - 1rem),
transparent
);
}
}
@layer components {
/* Hide asterisk (`*`) required indicator */
sl-input.hide-required-content {
--sl-input-required-content-color: transparent;
}
sl-input.input-font-monostyle::part(input) {
@apply font-monostyle;
}
sl-input[filled]::part(form-control-input) {
--sl-input-filled-background-color: theme(colors.slate.50);
--sl-input-filled-background-color-hover: var(
--sl-input-filled-background-color
);
}
sl-input[filled]::part(base) {
border: 1px solid theme(colors.gray.200);
border-radius: var(--sl-input-border-radius-small);
}
sl-textarea::part(textarea)::placeholder,
sl-input::part(input)::placeholder {
font-weight: var(--sl-font-weight-light);
}
sl-drawer::part(header) {
--header-spacing: var(--sl-spacing-small);
}
sl-drawer::part(title) {
font-size: var(--font-size-base);
font-weight: var(--sl-font-weight-medium);
line-height: 1.5;
}
sl-drawer::part(footer) {
border-top: 1px solid var(--sl-panel-border-color);
}
sl-button.button-card {
@apply w-full;
}
sl-button.button-card::part(base) {
@apply min-h-20 justify-between leading-none;
}
sl-button.button-card::part(label) {
@apply flex flex-1 flex-col justify-center gap-2 text-left;
}
}
/* Following styles won't work with layers */
.sl-toast-stack {
bottom: 0;
top: auto;
}
/* Ensure buttons in shadow dom inherit hover color */
[class^="hover\:text-"]::part(base):hover,
[class*=" hover\:text-"]::part(base):hover {
color: inherit;
}
/* Fix scrollbar gutter not actually */
html {
overflow: auto;
scrollbar-gutter: stable;
}
body.sl-scroll-lock {
scrollbar-gutter: auto !important;
}
/* Leave document scrollable now for replay.ts embedded dialogs */
/* html:has(body.sl-scroll-lock) {
overflow: hidden;
} */