From 977b7f6d4de0b518af4c08f6cae0359f9e3c88e0 Mon Sep 17 00:00:00 2001 From: Volodymyr Vreshch Date: Fri, 20 Mar 2026 22:10:30 +0100 Subject: [PATCH 1/2] chore: add prettier format:check to CI validation --- .github/workflows/pr-validation.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index cbcd2fb..73dd3f3 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -33,6 +33,9 @@ jobs: - name: Lint code run: npm run lint + - name: Format check + run: npm run format:check + - name: Build project run: npm run build From da189ef7cb010bb0a6478f9c0920481486066f5c Mon Sep 17 00:00:00 2001 From: Volodymyr Vreshch Date: Fri, 20 Mar 2026 22:13:59 +0100 Subject: [PATCH 2/2] chore: apply prettier formatting to existing files --- .github/dependabot.yml | 1 - .github/workflows/deploy.yml | 36 ++--- README.md | 40 +++--- docker-compose.yml | 16 +-- e2e/visual.ts | 2 +- public/index.html | 22 +-- public/manual/index.html | 2 +- public/screenshots/index.html | 2 +- scripts/compare-screenshots.js | 22 ++- src/app/apple-icon.tsx | 74 +++++----- src/app/design-system/page.tsx | 248 +++++++++++++++++++++++++------- src/app/documentation/page.tsx | 76 +++++++--- src/app/downloads/page.tsx | 23 ++- src/app/layout.tsx | 12 +- src/app/page.tsx | 27 +++- src/app/support/page.tsx | 70 ++++++--- src/components/navigation.tsx | 16 +-- src/components/theme-toggle.tsx | 4 +- src/data/documentation.tsx | 97 ++++++++++--- src/data/downloads.tsx | 30 +++- src/data/home.tsx | 60 +++++++- src/data/support.ts | 11 +- 22 files changed, 647 insertions(+), 244 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6d6d796..800e31f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -47,4 +47,3 @@ updates: all-actions: patterns: - '*' - diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 57a5ac3..f199097 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -57,18 +57,18 @@ jobs: run: | IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" TAG="${{ steps.set-tag.outputs.tag }}" - + echo "🏗️ Building image..." docker build \ --build-arg COMMIT_SHA="${{ github.sha }}" \ --build-arg BRANCH="${{ github.ref_name }}" \ --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ -t ${IMAGE}:${TAG} -t ${IMAGE}:latest . - + echo "📤 Pushing image..." docker push ${IMAGE}:${TAG} docker push ${IMAGE}:latest - + echo "✅ Image pushed successfully!" echo "📦 Image: ${IMAGE}:${TAG}" echo "📦 Image: ${IMAGE}:latest" @@ -90,7 +90,7 @@ jobs: echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts - + # Test SSH connection echo "Testing SSH connection..." ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no root@${{ secrets.SERVER_HOST }} "echo 'SSH connection successful'" @@ -102,7 +102,7 @@ jobs: echo "📦 Copying docker-compose.yml..." scp -i ~/.ssh/deploy_key docker-compose.yml root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ - + echo "📦 Copying deployment script..." scp -i ~/.ssh/deploy_key scripts/deploy.sh root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "chmod +x /opt/diffractwd-com/deploy.sh" @@ -111,10 +111,10 @@ jobs: id: deploy run: | IMAGE_TAG="${{ needs.build-and-push.outputs.image-tag }}" - + echo "🚀 Deploying to production..." echo "📦 Image tag: ${IMAGE_TAG}" - + ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} << EOF set -e cd /opt/diffractwd-com @@ -192,10 +192,10 @@ jobs: const commitMessage = `${{ github.event.head_commit.message }}` || 'Manual deployment'; const eventName = '${{ github.event_name }}'; const triggerType = eventName === 'workflow_dispatch' ? 'Manual' : 'Automatic (push)'; - + let status = '✅ SUCCESS'; let emoji = '🎉'; - + if (buildResult === 'failure') { status = '❌ FAILED - Build'; emoji = '🔨'; @@ -203,34 +203,34 @@ jobs: status = '❌ FAILED - Deployment'; emoji = '🚨'; } - + const summary = `${emoji} **Deployment ${status}** - + **Commit:** \`${commitSha.substring(0, 8)}\` **Message:** ${commitMessage} **Branch:** master **Trigger:** ${triggerType} - + **Pipeline Results:** - 🐳 Build & Push: ${buildResult === 'success' ? '✅' : '❌'} ${buildResult} - 🚀 Deployment: ${deployResult === 'success' ? '✅' : '❌'} ${deployResult} - + **Details:** - **Image Tag:** \`${imageTag}\` - **Registry:** ghcr.io/vreshch/diffractwd.com - **Server:** diffractwd.com - **Deployment URL:** https://diffractwd.com - + **Quick Actions:** - 📋 [Workflow Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - 🌐 [Visit Website](https://diffractwd.com) - 📦 [Registry](https://github.com/${{ github.repository }}/pkgs/container/diffractwd.com) - + --- ⏰ Generated at: \`${new Date().toISOString()}\``; - + console.log(summary); - + // Create commit status try { await github.rest.repos.createCommitStatus({ @@ -244,4 +244,4 @@ jobs: }); } catch (error) { console.log('Could not create commit status:', error.message); - } \ No newline at end of file + } diff --git a/README.md b/README.md index 533e267..9a569b9 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Website for the DiffractWD application — a free and open-source tool for powde ## Technologies -* React 19 & TypeScript -* Next.js 15 (App Router) -* Tailwind CSS 4 -* Vitest & Playwright for testing -* Docker with Traefik reverse proxy -* GitHub Actions CI/CD +- React 19 & TypeScript +- Next.js 15 (App Router) +- Tailwind CSS 4 +- Vitest & Playwright for testing +- Docker with Traefik reverse proxy +- GitHub Actions CI/CD ## Quick Start @@ -26,18 +26,18 @@ npm run dev ## Available Scripts -| Command | Description | -|---|---| -| `npm run dev` | Start local development server | -| `npm run build` | Build for production | -| `npm start` | Start production server (port 3001) | -| `npm run lint` | Run ESLint | -| `npm run format` | Format code with Prettier | -| `npm test` | Run unit tests (Vitest) | -| `npm run test:watch` | Run unit tests in watch mode | -| `npm run test:e2e` | Run E2E tests (Playwright) | -| `npm run test:e2e:ui` | Run E2E tests with UI | -| `npm run verify` | Full verification (type check, lint, build, test) | +| Command | Description | +| --------------------- | ------------------------------------------------- | +| `npm run dev` | Start local development server | +| `npm run build` | Build for production | +| `npm start` | Start production server (port 3001) | +| `npm run lint` | Run ESLint | +| `npm run format` | Format code with Prettier | +| `npm test` | Run unit tests (Vitest) | +| `npm run test:watch` | Run unit tests in watch mode | +| `npm run test:e2e` | Run E2E tests (Playwright) | +| `npm run test:e2e:ui` | Run E2E tests with UI | +| `npm run verify` | Full verification (type check, lint, build, test) | ## Docker @@ -52,5 +52,5 @@ Production deployment uses Docker Swarm with Traefik for automatic HTTPS. ## Contacts -* Website: [vreshch.com](https://vreshch.com) -* Email: vreshch@gmail.com +- Website: [vreshch.com](https://vreshch.com) +- Email: vreshch@gmail.com diff --git a/docker-compose.yml b/docker-compose.yml index 9973990..5cfeca4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,25 +21,25 @@ services: - traefik.enable=true - traefik.docker.network=traefik-public - traefik.constraint-label=traefik-public - + # HTTP Router (redirect to HTTPS, but allow ACME challenges) - traefik.http.routers.diffractwd-http.rule=Host(`diffractwd.com`) || Host(`www.diffractwd.com`) - traefik.http.routers.diffractwd-http.entrypoints=http - traefik.http.routers.diffractwd-http.middlewares=https-redirect - + # Create HTTPS redirect middleware that allows ACME challenges - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true - + # HTTPS Router - traefik.http.routers.diffractwd-https.rule=Host(`diffractwd.com`) || Host(`www.diffractwd.com`) - traefik.http.routers.diffractwd-https.entrypoints=https - traefik.http.routers.diffractwd-https.tls=true - traefik.http.routers.diffractwd-https.tls.certresolver=letsencrypt - + # Service configuration - traefik.http.services.diffractwd.loadbalancer.server.port=3001 - + resources: limits: cpus: '0.5' @@ -47,9 +47,9 @@ services: reservations: cpus: '0.25' memory: 128M - + healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:3001/"] + test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://127.0.0.1:3001/'] interval: 30s timeout: 10s retries: 3 @@ -57,4 +57,4 @@ services: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/e2e/visual.ts b/e2e/visual.ts index 89089c9..ee093bc 100644 --- a/e2e/visual.ts +++ b/e2e/visual.ts @@ -48,7 +48,7 @@ export async function waitForVisualStability(page: Page, timeout = 500): Promise export async function expectScreenshot( page: Page, name: string, - options: ScreenshotOptions = {}, + options: ScreenshotOptions = {} ): Promise { const mode = getVisualMode(); const opts = { ...DEFAULT_OPTIONS, ...options }; diff --git a/public/index.html b/public/index.html index 2914997..ed1afb9 100644 --- a/public/index.html +++ b/public/index.html @@ -1,14 +1,20 @@ - + - - + + - - - - + + + +
- + diff --git a/public/manual/index.html b/public/manual/index.html index 6c70bcf..18ecdcb 100644 --- a/public/manual/index.html +++ b/public/manual/index.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/public/screenshots/index.html b/public/screenshots/index.html index 6c70bcf..18ecdcb 100644 --- a/public/screenshots/index.html +++ b/public/screenshots/index.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/scripts/compare-screenshots.js b/scripts/compare-screenshots.js index 7b5c0e8..0da39a9 100644 --- a/scripts/compare-screenshots.js +++ b/scripts/compare-screenshots.js @@ -30,7 +30,9 @@ import pixelmatch from 'pixelmatch'; function listPngs(dir) { if (!existsSync(dir)) return []; - return readdirSync(dir).filter((f) => f.endsWith('.png')).sort(); + return readdirSync(dir) + .filter((f) => f.endsWith('.png')) + .sort(); } function readPng(filepath) { @@ -205,8 +207,12 @@ function generateHighlight(currentPath, diffImg, highlightPath) { for (let x = x1; x <= x2; x++) { const idx = (y * width + x) * 4; highlight.data[idx] = Math.round(255 * fillAlpha + highlight.data[idx] * (1 - fillAlpha)); - highlight.data[idx + 1] = Math.round(0 * fillAlpha + highlight.data[idx + 1] * (1 - fillAlpha)); - highlight.data[idx + 2] = Math.round(255 * fillAlpha + highlight.data[idx + 2] * (1 - fillAlpha)); + highlight.data[idx + 1] = Math.round( + 0 * fillAlpha + highlight.data[idx + 1] * (1 - fillAlpha) + ); + highlight.data[idx + 2] = Math.round( + 255 * fillAlpha + highlight.data[idx + 2] * (1 - fillAlpha) + ); } } } @@ -217,8 +223,12 @@ function generateHighlight(currentPath, diffImg, highlightPath) { const idx = i * 4; if (diffImg.data[idx + 3] > 0) { highlight.data[idx] = Math.round(255 * pixelAlpha + currImg.data[idx] * (1 - pixelAlpha)); - highlight.data[idx + 1] = Math.round(0 * pixelAlpha + currImg.data[idx + 1] * (1 - pixelAlpha)); - highlight.data[idx + 2] = Math.round(255 * pixelAlpha + currImg.data[idx + 2] * (1 - pixelAlpha)); + highlight.data[idx + 1] = Math.round( + 0 * pixelAlpha + currImg.data[idx + 1] * (1 - pixelAlpha) + ); + highlight.data[idx + 2] = Math.round( + 255 * pixelAlpha + currImg.data[idx + 2] * (1 - pixelAlpha) + ); highlight.data[idx + 3] = 255; } } @@ -263,7 +273,7 @@ function main() { if (!baseDir || !currentDir) { console.error( - 'Usage: node compare-screenshots.js [--output file.json] [--diff-dir dir] [--highlight-dir dir]', + 'Usage: node compare-screenshots.js [--output file.json] [--diff-dir dir] [--highlight-dir dir]' ); process.exit(1); } diff --git a/src/app/apple-icon.tsx b/src/app/apple-icon.tsx index e3ea0e7..832cf00 100644 --- a/src/app/apple-icon.tsx +++ b/src/app/apple-icon.tsx @@ -5,45 +5,43 @@ export const contentType = 'image/png'; export default function AppleIcon() { return new ImageResponse( - ( -
+ - - - - -
- ), - { ...size }, + /> + + + , + { ...size } ); } diff --git a/src/app/design-system/page.tsx b/src/app/design-system/page.tsx index 6eabfbc..761e130 100644 --- a/src/app/design-system/page.tsx +++ b/src/app/design-system/page.tsx @@ -8,7 +8,15 @@ export const metadata: Metadata = { const isDev = process.env.NODE_ENV === 'development'; const DownloadIcon = () => ( - + @@ -16,20 +24,45 @@ const DownloadIcon = () => ( ); const ExternalLinkIcon = () => ( - + - + + ); const StarIcon = () => ( - + ); const CheckIcon = () => ( - + ); @@ -38,12 +71,31 @@ const CheckIcon = () => ( function FaviconVariantsSection() { return ( -
+
- - + +
@@ -52,7 +104,17 @@ function FaviconVariantsSection() { /* ─── Layout Helpers ─── */ -function Section({ id, title, subtitle, children }: { id: string; title: string; subtitle: string; children: React.ReactNode }) { +function Section({ + id, + title, + subtitle, + children, +}: { + id: string; + title: string; + subtitle: string; + children: React.ReactNode; +}) { return (
@@ -80,9 +142,7 @@ function ShowcaseBox({ label, children }: { label: string; children: React.React function GradientBox({ label, children }: { label: string; children: React.ReactNode }) { return (
-

- {label} -

+

{label}

{children}
); @@ -96,30 +156,46 @@ function Row({ children }: { children: React.ReactNode }) { function ButtonsSection() { return ( -
+
- - - - @@ -141,13 +217,23 @@ function BadgesSection() { Free & Open Source - Recommended + + Recommended + - v1.30 - v1.20 - .EXE - .ZIP + + v1.30 + + + v1.20 + + + .EXE + + + .ZIP + @@ -179,23 +265,41 @@ function CardsSection() {
-

Feature Card

-

Primary navy icon tint, cohesive with headings.

+

+ Feature Card +

+

+ Primary navy icon tint, cohesive with headings. +

- Recommended + + Recommended +
-

Download Card

-

Primary border on hover.

+

+ Download Card +

+

+ Primary border on hover. +

-

Info Card

+

+ Info Card +

    -
  • Bullet item one
  • -
  • Bullet item two
  • -
  • Bullet item three
  • +
  • + Bullet item one +
  • +
  • + Bullet item two +
  • +
  • + Bullet item three +
@@ -207,20 +311,30 @@ function CardsSection() { function IconsSection() { return ( -
+
-
+
+ +

32px

-
+
+ +

40px

-
+
+ +

48px

@@ -238,20 +352,27 @@ function TypographySection() {
-

Page Heading h1

+

+ Page Heading h1 +

-

Section Heading h2

+

+ Section Heading h2 +

-

Subsection h3

+

+ Subsection h3 +

Card Title

- Body text — used for descriptions, paragraphs, and general content throughout the site. + Body text — used for descriptions, paragraphs, and general content throughout the + site.

@@ -278,20 +399,33 @@ function LinksSection() {
- + External link with icon - Inline text with a linked phrase inside it. + Inline text with a{' '} + + linked phrase + {' '} + inside it. - + Link on gradient @@ -316,8 +450,12 @@ function StatsSection() { { value: 'MIT', label: 'License' }, ].map((stat) => (
-
{stat.value}
-
{stat.label}
+
+ {stat.value} +
+
+ {stat.label} +
))}
@@ -341,18 +479,30 @@ function TableSection() { - - - + + + {rows.map((r) => ( - + ))} diff --git a/src/app/documentation/page.tsx b/src/app/documentation/page.tsx index 00a92b4..a06e045 100644 --- a/src/app/documentation/page.tsx +++ b/src/app/documentation/page.tsx @@ -26,7 +26,15 @@ export default function DocumentationPage() {
+ } @@ -66,7 +74,15 @@ export default function DocumentationPage() {
+ @@ -87,10 +103,7 @@ export default function DocumentationPage() {
{fileFormats.map((row) => ( - + @@ -108,7 +121,15 @@ export default function DocumentationPage() {
+ @@ -133,9 +154,18 @@ export default function DocumentationPage() { + - + + } title="System Requirements" @@ -158,8 +188,17 @@ export default function DocumentationPage() { - + + + } title="Technical Details" @@ -191,7 +230,15 @@ export default function DocumentationPage() {
+ @@ -213,10 +260,7 @@ export default function DocumentationPage() { {modules.map((mod) => ( -
+
{mod.name} diff --git a/src/app/downloads/page.tsx b/src/app/downloads/page.tsx index e86df7d..62d28ad 100644 --- a/src/app/downloads/page.tsx +++ b/src/app/downloads/page.tsx @@ -57,9 +57,18 @@ export default function DownloadsPage() { + - + + } title="System Requirements" @@ -79,7 +88,15 @@ export default function DownloadsPage() { + } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 5e5affb..e7ac949 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -16,12 +16,8 @@ export const metadata: Metadata = { 'DiffractWD, powder diffraction software, powder pattern simulation, X-ray diffraction, crystallography, powder data visualization, free science software', authors: [{ name: 'Volodymyr D. Vreshch' }], icons: { - icon: [ - { url: '/icon.svg', type: 'image/svg+xml' }, - ], - apple: [ - { url: '/apple-icon', type: 'image/png', sizes: '180x180' }, - ], + icon: [{ url: '/icon.svg', type: 'image/svg+xml' }], + apple: [{ url: '/apple-icon', type: 'image/png', sizes: '180x180' }], }, openGraph: { type: 'website', @@ -30,7 +26,9 @@ export const metadata: Metadata = { description: 'Free open-source software for powder diffraction pattern manipulation, simulation, and visualization.', url: siteUrl, - images: [{ url: '/hero.jpg', width: 1200, height: 630, alt: 'DiffractWD application screenshot' }], + images: [ + { url: '/hero.jpg', width: 1200, height: 630, alt: 'DiffractWD application screenshot' }, + ], }, alternates: { canonical: '/', diff --git a/src/app/page.tsx b/src/app/page.tsx index 0f08398..bf39ade 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -12,7 +12,15 @@ export const metadata: Metadata = { }; const DownloadIcon = () => ( - + @@ -83,8 +91,8 @@ export default function HomePage() { Powder diffraction analysis made simple.

- Compare measured patterns, simulate from crystal data, and prepare - publication-ready figures — no crystallographic background required. + Compare measured patterns, simulate from crystal data, and prepare publication-ready + figures — no crystallographic background required.

@@ -166,9 +174,18 @@ export default function HomePage() { rel="noopener noreferrer" className="mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-accent hover:underline dark:text-accent-light" > - + - + + DOI: 10.1107/S0021889810044614 diff --git a/src/app/support/page.tsx b/src/app/support/page.tsx index c4aa9ba..dc5c2e2 100644 --- a/src/app/support/page.tsx +++ b/src/app/support/page.tsx @@ -15,10 +15,7 @@ export const metadata: Metadata = { export default function SupportPage() { return (
- +
{/* Author & Feedback */} @@ -27,7 +24,15 @@ export default function SupportPage() { + @@ -55,7 +60,15 @@ export default function SupportPage() { + } @@ -83,8 +96,17 @@ export default function SupportPage() {
- + + + } title="Changelog" @@ -94,11 +116,15 @@ export default function SupportPage() { {changelog.map((release, idx) => (
-
+
- + v{release.version} @@ -123,7 +149,15 @@ export default function SupportPage() {
+ } @@ -137,21 +171,21 @@ export default function SupportPage() { Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and - to permit persons to whom the Software is furnished to do so, subject to the following - conditions: + modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, subject to the + following conditions:

- The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all copies + or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - THE USE OR OTHER DEALINGS IN THE SOFTWARE. + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index 3e1e652..60a75b2 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -29,7 +29,7 @@ export function Navigation() { 'sticky top-0 z-50 transition-[background-color,border-color,box-shadow] duration-300', scrolled ? 'border-b border-border/60 bg-[#f0f4f8]/85 shadow-sm backdrop-blur-xl dark:border-dark-border/60 dark:bg-dark-bg/85' - : 'border-b border-transparent bg-[#f0f4f8] dark:bg-dark-bg', + : 'border-b border-transparent bg-[#f0f4f8] dark:bg-dark-bg' )} >
@@ -56,7 +56,7 @@ export function Navigation() { 'group relative px-3 py-2 text-sm font-medium transition-colors duration-200', isActive ? 'text-heading dark:text-dark-text' - : 'text-muted hover:text-heading dark:text-dark-text-secondary dark:hover:text-dark-text', + : 'text-muted hover:text-heading dark:text-dark-text-secondary dark:hover:text-dark-text' )} > {label} @@ -65,7 +65,7 @@ export function Navigation() { 'absolute inset-x-3 -bottom-[1px] h-[2px] rounded-full transition-all duration-300', isActive ? 'bg-primary dark:bg-accent-light' - : 'scale-x-0 bg-primary/60 group-hover:scale-x-100 dark:bg-accent-light/60', + : 'scale-x-0 bg-primary/60 group-hover:scale-x-100 dark:bg-accent-light/60' )} /> @@ -87,19 +87,19 @@ export function Navigation() {
@@ -110,7 +110,7 @@ export function Navigation() {
PropertyValueStatus + Property + + Value + + Status +
{r.prop} + {r.prop} + {r.val} - {r.status} + + {r.status} +
{row.category}