diff --git a/eslint-plugin-rill/index.js b/eslint-plugin-rill/index.js new file mode 100644 index 000000000000..2185896e5140 --- /dev/null +++ b/eslint-plugin-rill/index.js @@ -0,0 +1,7 @@ +import noDisallowedTailwindTextColors from "./no-disallowed-tailwind-colors.js"; + +export default { + rules: { + "no-disallowed-tailwind-text-colors": noDisallowedTailwindTextColors, + }, +}; diff --git a/eslint-plugin-rill/no-disallowed-tailwind-colors.js b/eslint-plugin-rill/no-disallowed-tailwind-colors.js new file mode 100644 index 000000000000..5de8386262ed --- /dev/null +++ b/eslint-plugin-rill/no-disallowed-tailwind-colors.js @@ -0,0 +1,91 @@ +/** + * ESLint rule to disallow certain Tailwind text color classes. + * Disallows: text-gray-*, text-neutral-*, text-slate-*, text-stone-*, text-zinc-* + */ + +const DISALLOWED_TEXT_PATTERN = + /\btext-(gray|neutral|slate|stone|zinc)-\d{1,3}\b/g; +const TEXT_ERROR_MESSAGE = + 'Disallowed Tailwind text color class: "{{ className }}". Use semantic color classes instead.'; + +const DISALLOWED_BACKGROUND_PATTERN = + /\bbg-(gray|neutral|slate|stone|zinc)-\d{1,3}\b/g; +const DISALLOWED_BACKGROUND_CLASSES = /\bbg-(white|black)\b/g; +const BACKGROUND_ERROR_MESSAGE = + 'Disallowed Tailwind background color class: "{{ className }}". Use semantic color classes instead.'; + +const DISALLOWED_CLASSES_PATTERNS = [ + [DISALLOWED_TEXT_PATTERN, TEXT_ERROR_MESSAGE], + + [DISALLOWED_BACKGROUND_PATTERN, BACKGROUND_ERROR_MESSAGE], + [DISALLOWED_BACKGROUND_CLASSES, BACKGROUND_ERROR_MESSAGE], +]; + +function reportAllMatches(value, context, node) { + if (typeof value !== "string") return; + + for (const [pattern, errorMessage] of DISALLOWED_CLASSES_PATTERNS) { + for (const match of value.matchAll(pattern)) { + context.report({ + node, + message: errorMessage, + data: { className: match[0] }, + }); + } + } +} + +export default { + meta: { + type: "problem", + docs: { + description: + "Disallow non-semantic Tailwind text/background color classes (gray, neutral, slate, stone, zinc)", + }, + schema: [], + }, + create(context) { + const sourceCode = context.sourceCode ?? context.getSourceCode(); + + return { + // Check Svelte HTML attributes (class="..." and className="...") + SvelteAttribute(node) { + if (node.key?.name === "class" || node.key?.name === "className") { + for (const valueNode of node.value) { + if (valueNode.type === "SvelteLiteral") { + reportAllMatches(valueNode.value, context, valueNode); + } + } + } + }, + // Check Svelte shorthand class directives (class:text-gray-500) + SvelteDirective(node) { + if (node.kind === "Class" && node.key?.name) { + const className = node.key.name.name || node.key.name; + reportAllMatches(className, context, node); + } + }, + // Check Svelte diff --git a/web-common/src/features/alerts/PreviewEmpty.svelte b/web-common/src/features/alerts/PreviewEmpty.svelte index 62aeda311de2..44383411e797 100644 --- a/web-common/src/features/alerts/PreviewEmpty.svelte +++ b/web-common/src/features/alerts/PreviewEmpty.svelte @@ -6,7 +6,7 @@
- +
{topLine}
diff --git a/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte b/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte index c10266bafa40..78750bd6c968 100644 --- a/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte +++ b/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte @@ -6,7 +6,7 @@
- +

{m.alert_no_filters_heading()} diff --git a/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte b/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte index 642e1ccfa3e6..60b4f5bf269a 100644 --- a/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte +++ b/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte @@ -41,7 +41,7 @@