Files
openobserve/web/src/styles/utilities.css
T

207 lines
6.9 KiB
CSS

/* Copyright 2026 OpenObserve Inc. */
/* ============================================================
UTILITIES — app-level utility classes (O2_STYLE_MIGRATION_PLAN.md §3).
A rule belongs here when BOTH hold:
1. it can't be a Tailwind utility in the template — needs a pseudo-element,
a non-utility property, or a runtime-generated node;
2. it's a reusable app-level treatment, not one component's private look.
Use `@utility`, not a plain `.class`: it lands in @layer utilities, so
variants (hover:, dark:) and the normal cascade work.
Colours via var(--color-*) only, never a raw hex. rem units (1px hairlines
excepted).
============================================================ */
/* ── Gradient backgrounds ───────────────────────────────────────────────────
The --color-gradient-* tokens are deliberately NOT in @theme: a @theme colour
would generate `background-color: <gradient>`, which is invalid and dropped.
They're background-IMAGES, so they get hand-written utilities. Values stay in
the token layer, so dark.css overrides still apply. Declared on demand. */
@utility bg-gradient-ai {
background-image: var(--color-gradient-ai);
}
@utility bg-gradient-ai-subtle {
background-image: var(--color-gradient-ai-subtle);
}
@utility bg-gradient-ai-faint {
background-image: var(--color-gradient-ai-faint);
}
@utility bg-gradient-brand-ribbon {
background-image: var(--color-gradient-brand-ribbon);
}
@utility bg-gradient-notification {
background-image: var(--color-gradient-notification);
}
@utility bg-gradient-danger {
background-image: var(--color-gradient-danger);
}
@utility bg-gradient-danger-hover {
background-image: var(--color-gradient-danger-hover);
}
/* Same thing under a different name: a linear-gradient token used as a fill. */
@utility bg-chat-bubble-user {
background-image: var(--color-chat-bubble-user);
}
/* Diagonal hatch marking a span that exists but cannot be shown. Consumer: components/rum/ReplayLoadBand.vue. */
@utility bg-hatch-unavailable {
background-image: repeating-linear-gradient(
45deg,
var(--color-surface-subtle-hover) 0 0.1875rem,
transparent 0.1875rem 0.4375rem
);
}
/* Hatch over a filled cell whose period is still in progress. Consumer: components/rum/productAnalytics/RetentionGrid.vue. */
@utility bg-hatch {
background-image: repeating-linear-gradient(
135deg,
color-mix(in srgb, var(--color-border-strong) 55%, transparent) 0 0.125rem,
transparent 0.125rem 0.375rem
);
}
/* Previous-period bar in a compared funnel. Consumer: components/rum/productAnalytics/funnelParts/FunnelStepBar.vue. */
@utility bg-hatch-period {
background-image: repeating-linear-gradient(
135deg,
var(--color-progress-bar-default) 0 0.125rem,
color-mix(in srgb, var(--color-progress-bar-default) 22%, transparent) 0.125rem 0.3125rem
);
}
/* ── Drag-and-drop row affordances ──────────────────────────────────────────
Sortable adds these classes to a row CLONE it builds at runtime, so no
template can reach it and the name must be a single token. `!important`
reproduces what the old scoped rules got for free — outranking the row's own
utilities. Consumer: lib/core/Table/sub-components/OTableBody.vue. */
@utility table-drag-ghost {
opacity: 0.3 !important;
background: var(--color-primary-50) !important;
/* eslint-disable-next-line local/no-hardcoded-px -- hairline: a 1-device-pixel drag outline must not scale with text */
border: 1px dashed var(--color-accent) !important;
border-radius: var(--radius-default) !important;
}
@utility table-drag-dragging {
opacity: 0.5 !important;
box-shadow: var(--shadow-lg) !important;
}
/* License-locked page: controls, drag handles and splitters lose pointer input and look disabled, while scroll containers and FeatureLockExempt navigation stay live. Consumer: components/common/FeatureLockBoundary.vue. */
@utility feature-locked-content {
&
:is(
a[href],
button,
input,
select,
textarea,
label,
summary,
[contenteditable="true"],
[role="button"],
[role="link"],
[role="tab"],
[role="checkbox"],
[role="radio"],
[role="switch"],
[role="combobox"],
[role="menuitem"],
[role="option"],
[role="slider"],
[role="separator"],
[draggable="true"],
.vue-flow__node,
.vue-flow__handle,
.vue-flow__edge,
.q-btn,
.q-field,
.q-toggle,
.q-checkbox,
.q-radio,
.q-tab,
.q-item--clickable
):not([data-feature-lock-exempt] *) {
pointer-events: none;
}
&
:is(a[href], button, .q-btn, .q-field, .q-toggle, .q-checkbox, .q-radio, .q-tab):not(
:disabled,
[aria-disabled="true"],
[data-o2-btn],
[data-feature-lock-exempt] *
) {
color: var(--color-text-disabled);
opacity: 0.6;
}
}
/* Announcement message markup comes from v-html, so links and code inherit the operator-chosen banner colour. */
@utility announcement-message {
overflow-wrap: anywhere;
& a,
& a:hover {
color: inherit;
font-weight: var(--font-weight-semibold);
text-decoration: underline;
}
& a:hover {
opacity: 0.8;
}
& code {
font-family: var(--font-mono);
padding-inline: 0.25rem;
border-radius: var(--radius-default);
background-color: color-mix(in srgb, currentColor 14%, transparent);
}
}
@utility bg-hatched {
/* eslint-disable-next-line local/no-hardcoded-px -- hairline: 1 device pixel */
--hatch-line: 1px;
background-color: var(--color-surface-subtle);
background-image: repeating-linear-gradient(
135deg,
var(--color-border-strong) 0 var(--hatch-line),
transparent var(--hatch-line) 0.3125rem
);
}
/* At a fractional device pixel ratio the browser blurs a canvas by resampling it; print keeps smoothing since its scale is arbitrary. */
@utility chart-canvas-pixelated {
& canvas {
image-rendering: pixelated;
}
@media print {
& canvas {
image-rendering: auto;
}
}
}
/* Green-to-red scale for the click heat legend; hues mirror the canvas palette in utils/rum/clickHeatmap.ts. */
@utility bg-heat-legend {
background-image: linear-gradient(
90deg,
var(--color-status-positive),
var(--color-warning),
var(--color-status-negative)
);
}
/* Thin ring cut around a glyph so it stays legible when it overlaps another icon. */
@utility lock-halo {
filter: drop-shadow(0.09375rem 0 0 var(--color-surface-chrome-deeper))
drop-shadow(-0.09375rem 0 0 var(--color-surface-chrome-deeper))
drop-shadow(0 0.09375rem 0 var(--color-surface-chrome-deeper))
drop-shadow(0 -0.09375rem 0 var(--color-surface-chrome-deeper));
}
/* Bare amber lock glyph, no container: the one look for every lock icon. */
@utility lock-chip {
@apply text-icon-locked;
}