From a25be12b32c31a64cffede02cccb388aeb0551cd Mon Sep 17 00:00:00 2001
From: Vuong <3168632+vuon9@users.noreply.github.com>
Date: Wed, 17 Jun 2026 14:06:43 +0700
Subject: [PATCH] Polish tool font and border consistency
---
frontend/e2e/tool-style-consistency.spec.js | 108 ++++++++++++++++++
.../src/components/inputs/ToolCopyButton.jsx | 2 +-
frontend/src/components/inputs/ToolInput.jsx | 2 +-
.../src/components/inputs/ToolInputGroup.jsx | 2 +-
frontend/src/pages/BarcodeGenerator.jsx | 2 +-
frontend/src/pages/CodeConverter/index.jsx | 2 +-
frontend/src/pages/CodeEncoder/index.jsx | 2 +-
frontend/src/pages/CodeEncrypter/index.jsx | 2 +-
frontend/src/pages/ColorConverter/index.jsx | 12 +-
frontend/src/pages/CronJobParser.jsx | 20 ++--
frontend/src/pages/DataGenerator/index.jsx | 2 +-
.../src/pages/DateTimeConverter/index.jsx | 4 +-
.../components/MultiHashOutput.jsx | 2 +-
frontend/src/pages/HashGenerator/index.jsx | 4 +-
frontend/src/pages/RegExpTester.jsx | 6 +-
frontend/src/pages/TextDiffChecker/index.jsx | 6 +-
frontend/src/pages/TextUtilities/index.jsx | 2 +-
17 files changed, 144 insertions(+), 36 deletions(-)
create mode 100644 frontend/e2e/tool-style-consistency.spec.js
diff --git a/frontend/e2e/tool-style-consistency.spec.js b/frontend/e2e/tool-style-consistency.spec.js
new file mode 100644
index 0000000..0f01a41
--- /dev/null
+++ b/frontend/e2e/tool-style-consistency.spec.js
@@ -0,0 +1,108 @@
+import { test, expect } from '@playwright/test';
+
+const TOOLS = [
+ 'code-encoder',
+ 'code-encrypter',
+ 'hash-generator',
+ 'code-converter',
+ 'text-utilities',
+ 'number-converter',
+ 'datetime-converter',
+ 'jwt',
+ 'barcode',
+ 'data-generator',
+ 'code-formatter',
+ 'color-converter',
+ 'url-inspector',
+ 'cron',
+ 'regexp',
+ 'diff',
+];
+
+const THEMES = [
+ { mode: 'light', name: 'github-light' },
+ { mode: 'dark', name: 'github-dark' },
+];
+
+async function setTheme(page, theme) {
+ await page.evaluate(({ mode, name }) => {
+ localStorage.setItem('dt-mode', mode);
+ localStorage.setItem('dt-name', name);
+ }, theme);
+}
+
+test.describe('Tool visual style consistency', () => {
+ for (const theme of THEMES) {
+ for (const slug of TOOLS) {
+ test(`${slug} keeps tool text and borders consistent in ${theme.mode}`, async ({ page }) => {
+ await page.goto(`/tool/${slug}`);
+ await setTheme(page, theme);
+ await page.goto(`/tool/${slug}`);
+ await page.waitForLoadState('networkidle');
+
+ const issues = await page.evaluate(() => {
+ const isVisible = (element, style) => {
+ const rect = element.getBoundingClientRect();
+ return (
+ rect.width > 0 &&
+ rect.height > 0 &&
+ style.visibility !== 'hidden' &&
+ style.display !== 'none' &&
+ style.opacity !== '0'
+ );
+ };
+
+ const selector = 'main, [data-testid="tool-page"], [role="main"]';
+ const root = document.querySelector(selector) ?? document.body;
+
+ return Array.from(root.querySelectorAll('*')).flatMap((element) => {
+ const style = getComputedStyle(element);
+ if (!isVisible(element, style)) return [];
+
+ const rect = element.getBoundingClientRect();
+ const text = element.textContent?.replace(/\s+/g, ' ').trim() ?? '';
+ const tag = element.tagName.toLowerCase();
+ const classes = element.className?.toString?.() ?? '';
+ const elementIssues = [];
+
+ const fontSize = parseFloat(style.fontSize);
+ const hasOwnText =
+ text.length > 0 &&
+ Array.from(element.children).every((child) => child.textContent?.trim() !== text);
+
+ if (hasOwnText && fontSize > 0 && fontSize < 11) {
+ elementIssues.push({
+ kind: 'font-size',
+ tag,
+ classes,
+ text: text.slice(0, 80),
+ value: style.fontSize,
+ });
+ }
+
+ const borderWidths = [
+ style.borderTopWidth,
+ style.borderRightWidth,
+ style.borderBottomWidth,
+ style.borderLeftWidth,
+ ].map(parseFloat);
+
+ if (rect.width > 8 && rect.height > 8 && borderWidths.some((width) => width > 2)) {
+ elementIssues.push({
+ kind: 'border-width',
+ tag,
+ classes,
+ text: text.slice(0, 80),
+ value: borderWidths.join('/'),
+ });
+ }
+
+ return elementIssues;
+ });
+ });
+
+ expect(issues).toEqual([]);
+ });
+ }
+ }
+});
diff --git a/frontend/src/components/inputs/ToolCopyButton.jsx b/frontend/src/components/inputs/ToolCopyButton.jsx
index 805db80..6ca4f90 100644
--- a/frontend/src/components/inputs/ToolCopyButton.jsx
+++ b/frontend/src/components/inputs/ToolCopyButton.jsx
@@ -42,7 +42,7 @@ export function ToolCopyButton({
size={size}
onClick={handleCopy}
disabled={isDisabled}
- className={cn('h-7 gap-1.5 text-[10px] font-bold uppercase tracking-wider', className)}
+ className={cn('h-7 gap-1.5 text-[11px] font-bold uppercase tracking-wider', className)}
>
{copied ?