@simmalugnt-se/payload-content-health 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ - The dashboard widget is a summary: a ring for the share in order, and one row per category (SEO,
6
+ Structure, Translations, Accessibility) with a bar and "N to fix". It no longer lists documents;
7
+ each row opens the work list on its category, and "Open details" opens the list.
8
+ - The work list shows one category at a time as tabs, with the number of findings on each and the
9
+ category with most to fix open first. Under the tabs, every check has its own section with the
10
+ documents that need work, and its own "Fix N with the assistant" next to the heading. The check
11
+ filter and "Clear filters" are gone; collection and locale remain as selects where there is more
12
+ than one. `?category=` is the new address parameter; `?check=` still opens that check's category.
13
+ - Red and amber mark what needs work, next to the blue accent. Colors are in `styles/tokens.css`.
14
+ - `CATEGORY_IDS`, `categoryOf` and `categoryStats` are exported.
15
+
16
+ ## 0.5.2
17
+
18
+ - Work-list filters use Payload's ReactSelect with its standard menu and focus styling.
19
+ Filters, Clear filters and individual and batch assistant buttons share one control height.
20
+ The filter row fills the available width, with Clear filters aligned to the batch action below.
21
+ - The workspace dev app now includes content health alongside the editor assistant and visual
22
+ editing, with alt text, SEO, heading, thin content and translation checks on its seed data.
23
+ - Source builds typecheck with the host app's generated collection and locale types.
24
+
3
25
  ## 0.5.1
4
26
 
5
27
  - The assistant's button now shows in the header of the work list. The view did not pass Admin's
package/README.md CHANGED
@@ -112,14 +112,22 @@ The plugin registers the widget `content-health`. When the project sets no
112
112
  widget. Payload keeps each editor's own layout as a preference once they edit the dashboard; they add
113
113
  the widget from the dashboard's edit mode, and can limit it to some checks in its settings.
114
114
 
115
- Pass `addToDefaultLayout: false` to only register the widget. When a check has more documents than
116
- fit in its tile, "N more" opens the work list filtered on that check.
115
+ The widget is a summary: the share of checked values in order, and one row per category with a bar
116
+ and how much there is to fix. Categories group the checks: SEO (meta titles and descriptions, their
117
+ lengths, share images), Structure (headings, page length), Translations and Accessibility (alt
118
+ texts). A category none of the configured checks belong to is left out. Each row opens the work list
119
+ on that category, and "Open details" opens the list itself.
120
+
121
+ Pass `addToDefaultLayout: false` to only register the widget.
117
122
 
118
123
  ## Work list
119
124
 
120
- `/admin/content-health` (linked at the top of the nav) lists every finding, filterable by check,
121
- collection and locale. The filters are kept in the address, e.g.
122
- `/admin/content-health?check=seo.title-missing&locale=sv`. The view scans once per visit.
125
+ `/admin/content-health` (linked at the top of the nav) shows one category at a time as tabs, each
126
+ with its number of findings, and under them one section per check with the documents that need work.
127
+ The category with most to fix opens first. Where the project has several collections or locales, two
128
+ selects narrow the list. The tab and the selects are kept in the address, e.g.
129
+ `/admin/content-health?category=seo&locale=sv`; an older link with `?check=seo.title-missing` opens
130
+ that check's category. The view scans once per visit.
123
131
 
124
132
  Each row opens the document in the finding's locale with the field brought into view: tabs and
125
133
  collapsed rows are opened, and the field is scrolled to, focused and highlighted. A finding in a row
@@ -147,10 +155,10 @@ Both parameters are removed from the address once read. `editURL(adminRoute, fin
147
155
 
148
156
  ### Many documents at once
149
157
 
150
- Where the assistant allows `content.update` (0.11.0 or later), a list filtered to missing alt texts,
151
- meta titles or descriptions (missing or the wrong length) or missing translations offers "Fix N with
152
- the assistant" above the rows. It opens the assistant's panel beside the list with up to 20 of the
153
- documents shown and one prompt for all of them; the assistant proposes a change per document, and
158
+ Where the assistant allows `content.update` (0.11.0 or later), the sections for missing alt texts,
159
+ meta titles or descriptions (missing or the wrong length) and missing translations offer "Fix N with
160
+ the assistant" next to their heading. It opens the assistant's panel beside the list with up to 20 of
161
+ the documents in the section and one prompt for all of them; the assistant proposes a change per document, and
154
162
  the editor saves the ones they want. Saved documents drop out of the list. `batchURL(adminRoute,
155
163
  filters, targets, prompt)` and `batchTarget(finding)` build the link.
156
164
 
@@ -0,0 +1,21 @@
1
+ import type { CheckStats } from "./group.ts";
2
+ import type { CheckId } from "./types.ts";
3
+ /** What an editor sorts the checks by: the order tabs and rows come in. */
4
+ export declare const CATEGORY_IDS: readonly ["seo", "structure", "translations", "accessibility"];
5
+ export type CategoryId = (typeof CATEGORY_IDS)[number];
6
+ export declare const CATEGORY_CHECKS: Record<CategoryId, readonly CheckId[]>;
7
+ export declare function categoryOf(check: CheckId): CategoryId;
8
+ export type CategoryStats = {
9
+ category: CategoryId;
10
+ /** Field values the category's checks applied to. */
11
+ checked: number;
12
+ /** Values with a finding. */
13
+ failing: number;
14
+ };
15
+ /** Per category with at least one check that ran, in `CATEGORY_IDS` order. */
16
+ export declare function categoryStats(stats: CheckStats[]): CategoryStats[];
17
+ /** How a category reads at a glance: nothing to measure, all in order, mostly in order, or not. */
18
+ export type Tone = "none" | "ok" | "warn" | "bad";
19
+ export declare function categoryTone({ checked, failing, }: Pick<CategoryStats, "checked" | "failing">): Tone;
20
+ /** The category to open first: the one with most to fix, else the first. */
21
+ export declare function defaultCategory(stats: CategoryStats[]): CategoryId | undefined;
@@ -0,0 +1,43 @@
1
+ /** What an editor sorts the checks by: the order tabs and rows come in. */
2
+ export const CATEGORY_IDS = ["seo", "structure", "translations", "accessibility"];
3
+ export const CATEGORY_CHECKS = {
4
+ seo: [
5
+ "seo.title-missing",
6
+ "seo.title-length",
7
+ "seo.description-missing",
8
+ "seo.description-length",
9
+ "seo.image-missing",
10
+ ],
11
+ structure: ["content.h1-missing", "content.h1-multiple", "content.heading-skip", "content.thin"],
12
+ translations: ["content.untranslated"],
13
+ accessibility: ["media.alt-missing"],
14
+ };
15
+ export function categoryOf(check) {
16
+ return CATEGORY_IDS.find((id) => CATEGORY_CHECKS[id].includes(check));
17
+ }
18
+ /** Per category with at least one check that ran, in `CATEGORY_IDS` order. */
19
+ export function categoryStats(stats) {
20
+ return CATEGORY_IDS.flatMap((category) => {
21
+ const own = stats.filter((stat) => categoryOf(stat.check) === category);
22
+ return own.length
23
+ ? [
24
+ {
25
+ category,
26
+ checked: own.reduce((sum, stat) => sum + stat.checked, 0),
27
+ failing: own.reduce((sum, stat) => sum + stat.failing, 0),
28
+ },
29
+ ]
30
+ : [];
31
+ });
32
+ }
33
+ export function categoryTone({ checked, failing, }) {
34
+ if (!checked)
35
+ return failing ? "bad" : "none";
36
+ if (!failing)
37
+ return "ok";
38
+ return (checked - failing) / checked >= 0.5 ? "warn" : "bad";
39
+ }
40
+ /** The category to open first: the one with most to fix, else the first. */
41
+ export function defaultCategory(stats) {
42
+ return stats.reduce((best, stat) => (!best || stat.failing > best.failing ? stat : best), undefined)?.category;
43
+ }
package/dist/copy.d.ts CHANGED
@@ -1,13 +1,10 @@
1
1
  /** Everything the widget and the work list say, in Admin's language. */
2
+ import type { CategoryId } from "./categories.ts";
2
3
  import type { CheckId, Finding } from "./types.ts";
3
4
  export type UiLanguage = "sv" | "en";
4
5
  export declare function uiLanguage(adminLanguage: string | undefined): UiLanguage;
5
6
  export declare const CHECK_LABELS: Record<UiLanguage, Record<CheckId, string>>;
6
- /** Tile headings: what is measured, so "0 of 4 filled in" reads without a double negative. */
7
- export declare const TILE_LABELS: Record<UiLanguage, Record<CheckId, string>>;
8
- type Status = (ok: number, total: number) => string;
9
- /** A tile's "x of y" line, phrased as what is in order for that check. */
10
- export declare const STATUS: Record<UiLanguage, Record<CheckId, Status>>;
7
+ export declare const CATEGORY_LABELS: Record<UiLanguage, Record<CategoryId, string>>;
11
8
  export declare const COPY: {
12
9
  readonly en: {
13
10
  readonly title: "Content health";
@@ -17,8 +14,8 @@ export declare const COPY: {
17
14
  readonly ok: (ok: number, total: number) => string;
18
15
  readonly checkPasses: "All good";
19
16
  readonly nothingYet: "Nothing to measure yet";
20
- readonly passing: (count: number) => string;
21
- readonly more: (count: number) => string;
17
+ readonly toFix: (count: number) => string;
18
+ readonly openDetails: "Open details";
22
19
  readonly length: (actual: number, min: number, max: number) => string;
23
20
  readonly headingSkip: (previous: number, level: number) => string;
24
21
  readonly h1Count: (count: number) => string;
@@ -34,8 +31,8 @@ export declare const COPY: {
34
31
  readonly ok: (ok: number, total: number) => string;
35
32
  readonly checkPasses: "Allt i ordning";
36
33
  readonly nothingYet: "Inget att mäta än";
37
- readonly passing: (count: number) => string;
38
- readonly more: (count: number) => string;
34
+ readonly toFix: (count: number) => string;
35
+ readonly openDetails: "Öppna detaljer";
39
36
  readonly length: (actual: number, min: number, max: number) => string;
40
37
  readonly headingSkip: (previous: number, level: number) => string;
41
38
  readonly h1Count: (count: number) => string;
@@ -62,13 +59,12 @@ export declare const LIST_COPY: {
62
59
  readonly nav: "Content health";
63
60
  readonly intro: "Everything the checks found, in the latest version of each document, drafts included.";
64
61
  readonly summary: (findings: number, documents: number) => string;
65
- readonly check: "Check";
62
+ readonly categories: "Categories";
66
63
  readonly collection: "Collection";
67
64
  readonly locale: "Locale";
68
65
  readonly all: "All";
69
- readonly clear: "Clear filters";
70
- readonly document: "Document";
71
- readonly issue: "Issue";
66
+ readonly documents: (count: number) => string;
67
+ readonly categoryOk: "Everything in this category is in order.";
72
68
  readonly draft: "Draft";
73
69
  readonly fix: "Fix with the assistant";
74
70
  readonly fixMany: (count: number, total: number) => string;
@@ -80,13 +76,12 @@ export declare const LIST_COPY: {
80
76
  readonly nav: "Innehållshälsa";
81
77
  readonly intro: "Allt kontrollerna hittade, i den senaste versionen av varje dokument, utkast inräknade.";
82
78
  readonly summary: (findings: number, documents: number) => string;
83
- readonly check: "Kontroll";
79
+ readonly categories: "Kategorier";
84
80
  readonly collection: "Samling";
85
81
  readonly locale: "Språk";
86
82
  readonly all: "Alla";
87
- readonly clear: "Rensa filter";
88
- readonly document: "Dokument";
89
- readonly issue: "Problem";
83
+ readonly documents: (count: number) => string;
84
+ readonly categoryOk: "Allt i den här kategorin är i ordning.";
90
85
  readonly draft: "Utkast";
91
86
  readonly fix: "Åtgärda med assistenten";
92
87
  readonly fixMany: (count: number, total: number) => string;
package/dist/copy.js CHANGED
@@ -29,62 +29,18 @@ export const CHECK_LABELS = {
29
29
  "content.untranslated": "Saknar översättning",
30
30
  },
31
31
  };
32
- /** Tile headings: what is measured, so "0 of 4 filled in" reads without a double negative. */
33
- export const TILE_LABELS = {
32
+ export const CATEGORY_LABELS = {
34
33
  en: {
35
- "media.alt-missing": "Alt texts",
36
- "seo.title-missing": "Meta titles",
37
- "seo.title-length": "Meta title length",
38
- "seo.description-missing": "Meta descriptions",
39
- "seo.description-length": "Meta description length",
40
- "seo.image-missing": "Share images",
41
- "content.h1-missing": "Main heading",
42
- "content.h1-multiple": "Single main heading",
43
- "content.heading-skip": "Heading order",
44
- "content.thin": "Page length",
45
- "content.untranslated": "Translations",
46
- },
47
- sv: {
48
- "media.alt-missing": "Alt-texter",
49
- "seo.title-missing": "Metatitlar",
50
- "seo.title-length": "Metatitlarnas längd",
51
- "seo.description-missing": "Metabeskrivningar",
52
- "seo.description-length": "Metabeskrivningarnas längd",
53
- "seo.image-missing": "Delningsbilder",
54
- "content.h1-missing": "Huvudrubrik",
55
- "content.h1-multiple": "En huvudrubrik",
56
- "content.heading-skip": "Rubrikordning",
57
- "content.thin": "Sidlängd",
58
- "content.untranslated": "Översättningar",
59
- },
60
- };
61
- /** A tile's "x of y" line, phrased as what is in order for that check. */
62
- export const STATUS = {
63
- en: {
64
- "media.alt-missing": (ok, total) => `${ok} of ${total} filled in`,
65
- "seo.title-missing": (ok, total) => `${ok} of ${total} filled in`,
66
- "seo.title-length": (ok, total) => `${ok} of ${total} the right length`,
67
- "seo.description-missing": (ok, total) => `${ok} of ${total} filled in`,
68
- "seo.description-length": (ok, total) => `${ok} of ${total} the right length`,
69
- "seo.image-missing": (ok, total) => `${ok} of ${total} filled in`,
70
- "content.h1-missing": (ok, total) => `${ok} of ${total} pages have an H1`,
71
- "content.h1-multiple": (ok, total) => `${ok} of ${total} pages have at most one`,
72
- "content.heading-skip": (ok, total) => `${ok} of ${total} pages in order`,
73
- "content.thin": (ok, total) => `${ok} of ${total} pages long enough`,
74
- "content.untranslated": (ok, total) => `${ok} of ${total} translated`,
34
+ seo: "SEO",
35
+ structure: "Structure",
36
+ translations: "Translations",
37
+ accessibility: "Accessibility",
75
38
  },
76
39
  sv: {
77
- "media.alt-missing": (ok, total) => `${ok} av ${total} ifyllda`,
78
- "seo.title-missing": (ok, total) => `${ok} av ${total} ifyllda`,
79
- "seo.title-length": (ok, total) => `${ok} av ${total} med rätt längd`,
80
- "seo.description-missing": (ok, total) => `${ok} av ${total} ifyllda`,
81
- "seo.description-length": (ok, total) => `${ok} av ${total} med rätt längd`,
82
- "seo.image-missing": (ok, total) => `${ok} av ${total} ifyllda`,
83
- "content.h1-missing": (ok, total) => `${ok} av ${total} sidor har en H1`,
84
- "content.h1-multiple": (ok, total) => `${ok} av ${total} sidor har högst en`,
85
- "content.heading-skip": (ok, total) => `${ok} av ${total} sidor i ordning`,
86
- "content.thin": (ok, total) => `${ok} av ${total} sidor tillräckligt långa`,
87
- "content.untranslated": (ok, total) => `${ok} av ${total} översatta`,
40
+ seo: "SEO",
41
+ structure: "Struktur",
42
+ translations: "Översättningar",
43
+ accessibility: "Tillgänglighet",
88
44
  },
89
45
  };
90
46
  export const COPY = {
@@ -96,8 +52,8 @@ export const COPY = {
96
52
  ok: (ok, total) => `${ok} of ${total} OK`,
97
53
  checkPasses: "All good",
98
54
  nothingYet: "Nothing to measure yet",
99
- passing: (count) => `${count} ${count === 1 ? "check passes" : "checks pass"}`,
100
- more: (count) => `${count} more`,
55
+ toFix: (count) => `${count} to fix`,
56
+ openDetails: "Open details",
101
57
  length: (actual, min, max) => `${actual} characters, aim for ${min}–${max}`,
102
58
  headingSkip: (previous, level) => `H${previous} → H${level}`,
103
59
  h1Count: (count) => `${count} H1s`,
@@ -113,8 +69,8 @@ export const COPY = {
113
69
  ok: (ok, total) => `${ok} av ${total} OK`,
114
70
  checkPasses: "Allt i ordning",
115
71
  nothingYet: "Inget att mäta än",
116
- passing: (count) => `${count} ${count === 1 ? "kontroll godkänd" : "kontroller godkända"}`,
117
- more: (count) => `${count} till`,
72
+ toFix: (count) => `${count} att åtgärda`,
73
+ openDetails: "Öppna detaljer",
118
74
  length: (actual, min, max) => `${actual} tecken, sikta på ${min}–${max}`,
119
75
  headingSkip: (previous, level) => `H${previous} → H${level}`,
120
76
  h1Count: (count) => `${count} H1:or`,
@@ -257,13 +213,12 @@ export const LIST_COPY = {
257
213
  nav: "Content health",
258
214
  intro: "Everything the checks found, in the latest version of each document, drafts included.",
259
215
  summary: (findings, documents) => `${findings} ${findings === 1 ? "issue" : "issues"} in ${documents} ${documents === 1 ? "document" : "documents"}`,
260
- check: "Check",
216
+ categories: "Categories",
261
217
  collection: "Collection",
262
218
  locale: "Locale",
263
219
  all: "All",
264
- clear: "Clear filters",
265
- document: "Document",
266
- issue: "Issue",
220
+ documents: (count) => `${count} ${count === 1 ? "document" : "documents"}`,
221
+ categoryOk: "Everything in this category is in order.",
267
222
  draft: "Draft",
268
223
  fix: "Fix with the assistant",
269
224
  fixMany: (count, total) => count < total
@@ -277,13 +232,12 @@ export const LIST_COPY = {
277
232
  nav: "Innehållshälsa",
278
233
  intro: "Allt kontrollerna hittade, i den senaste versionen av varje dokument, utkast inräknade.",
279
234
  summary: (findings, documents) => `${findings} problem i ${documents} dokument`,
280
- check: "Kontroll",
235
+ categories: "Kategorier",
281
236
  collection: "Samling",
282
237
  locale: "Språk",
283
238
  all: "Alla",
284
- clear: "Rensa filter",
285
- document: "Dokument",
286
- issue: "Problem",
239
+ documents: (count) => `${count} dokument`,
240
+ categoryOk: "Allt i den här kategorin är i ordning.",
287
241
  draft: "Utkast",
288
242
  fix: "Åtgärda med assistenten",
289
243
  fixMany: (count, total) => count < total
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { CategoryId, CategoryStats } from "./categories.ts";
2
+ export { CATEGORY_IDS, categoryOf, categoryStats } from "./categories.ts";
1
3
  export type { DocumentInput, DocumentResult, FieldRule, ResolvedRule } from "./checks.ts";
2
4
  export { checkDocument, DEFAULT_MIN_WORDS, rulesFor, SEO_DEFAULTS } from "./checks.ts";
3
5
  export type { Heading, PageContent } from "./content.ts";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { CATEGORY_IDS, categoryOf, categoryStats } from "./categories.js";
1
2
  export { checkDocument, DEFAULT_MIN_WORDS, rulesFor, SEO_DEFAULTS } from "./checks.js";
2
3
  export { countWords, readContent } from "./content.js";
3
4
  export { checkStats, countDocuments, groupFindings } from "./group.js";
package/dist/links.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type CategoryId } from "./categories.ts";
1
2
  import { type CheckId, type Finding } from "./types.ts";
2
3
  /** Admin path of the work list. */
3
4
  export declare const VIEW_PATH = "/content-health";
@@ -62,7 +63,12 @@ export declare function batchTarget(finding: Finding): string;
62
63
  export declare function batchURL(adminRoute: string, filters: ListFilters, targets: string[], ask: string): string;
63
64
  /** The document in the finding's locale with its field brought into view, and a prompt when given. */
64
65
  export declare function editURL(adminRoute: string, finding: Finding, ask?: string): string;
66
+ /**
67
+ * The work list's filters. `category` picks the tab. `check` is only an entry point (an older link,
68
+ * or a batch link): the view turns it into its category and `check` stays out of the state.
69
+ */
65
70
  export type ListFilters = {
71
+ category?: CategoryId;
66
72
  check?: CheckId;
67
73
  collection?: string;
68
74
  locale?: string;
package/dist/links.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * the client bridge build and read the same addresses.
5
5
  */
6
6
  import { formatAdminURL } from "payload/shared";
7
+ import { CATEGORY_IDS, categoryOf } from "./categories.js";
7
8
  import { CHECK_IDS } from "./types.js";
8
9
  /** Admin path of the work list. */
9
10
  export const VIEW_PATH = "/content-health";
@@ -128,7 +129,7 @@ export function listURL(adminRoute, filters = {}) {
128
129
  }
129
130
  export function filterQuery(filters) {
130
131
  const params = new URLSearchParams();
131
- for (const key of ["check", "collection", "locale"]) {
132
+ for (const key of ["category", "check", "collection", "locale"]) {
132
133
  const value = filters[key];
133
134
  if (value) {
134
135
  params.set(key, value);
@@ -142,17 +143,22 @@ export function readFilters(searchParams) {
142
143
  const value = searchParams?.[key];
143
144
  return (Array.isArray(value) ? value[0] : value) || undefined;
144
145
  };
146
+ const category = first("category");
145
147
  const check = first("check");
146
148
  const collection = first("collection");
147
149
  const locale = first("locale");
148
150
  return {
151
+ ...(category && CATEGORY_IDS.includes(category)
152
+ ? { category: category }
153
+ : {}),
149
154
  ...(check && CHECK_IDS.includes(check) ? { check: check } : {}),
150
155
  ...(collection ? { collection } : {}),
151
156
  ...(locale ? { locale } : {}),
152
157
  };
153
158
  }
154
159
  export function matchesFilters(finding, filters) {
155
- return ((!filters.check || finding.check === filters.check) &&
160
+ return ((!filters.category || categoryOf(finding.check) === filters.category) &&
161
+ (!filters.check || finding.check === filters.check) &&
156
162
  (!filters.collection || finding.collection === filters.collection) &&
157
163
  // Unlocalized fields belong to every locale.
158
164
  (!filters.locale || !finding.locale || finding.locale === filters.locale));
package/dist/scan.js CHANGED
@@ -31,7 +31,7 @@ export async function scanContentHealth({ payload, user, checks }) {
31
31
  ? payload.config.localization.localeCodes
32
32
  : [undefined];
33
33
  for (const [slug, collectionOptions] of Object.entries(options.collections)) {
34
- const collection = payload.collections[slug]?.config;
34
+ const collection = payload.config.collections.find((collection) => collection.slug === slug);
35
35
  if (!collection) {
36
36
  result.problems.push(`Collection "${slug}" does not exist.`);
37
37
  continue;
@@ -95,7 +95,7 @@ export async function scanContentHealth({ payload, user, checks }) {
95
95
  depth: 0,
96
96
  draft: drafts,
97
97
  fallbackLocale: false,
98
- ...(locale ? { locale } : {}),
98
+ ...(locale ? { locale: locale } : {}),
99
99
  overrideAccess: false,
100
100
  pagination: false,
101
101
  select: select,
@@ -159,7 +159,7 @@ async function scanTranslations(input) {
159
159
  depth: 0,
160
160
  draft: input.drafts,
161
161
  fallbackLocale: false,
162
- locale,
162
+ locale: locale,
163
163
  overrideAccess: false,
164
164
  pagination: false,
165
165
  user: input.user,
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Colors shared by the widget and the work list. The accent is the blue the editor assistant and
3
+ * visual editing use; red and amber mark what needs work. The text tones are darker, so small text
4
+ * keeps its contrast on Payload's light background.
5
+ */
6
+ .content-health,
7
+ .content-health-list {
8
+ --content-health-accent: #2563eb;
9
+ --content-health-accent-text: #2563eb;
10
+ --content-health-accent-tint: rgba(37, 99, 235, 0.1);
11
+ --content-health-bad: #dc2626;
12
+ --content-health-bad-text: #b91c1c;
13
+ --content-health-warn: #d97706;
14
+ --content-health-warn-text: #b45309;
15
+ }
16
+
17
+ html[data-theme="dark"] .content-health,
18
+ html[data-theme="dark"] .content-health-list {
19
+ --content-health-accent: #60a5fa;
20
+ --content-health-accent-text: #60a5fa;
21
+ --content-health-accent-tint: rgba(96, 165, 250, 0.14);
22
+ --content-health-bad: #f87171;
23
+ --content-health-bad-text: #f87171;
24
+ --content-health-warn: #fbbf24;
25
+ --content-health-warn-text: #fbbf24;
26
+ }