diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index 3193e84..f695a36 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -295,7 +295,7 @@ jobs:
}
// Page status table
- const pages = ['home', 'news', 'about', 'screenshots', 'downloads', 'quick-manual', 'support', 'license'];
+ const pages = ['home', 'screenshots', 'documentation', 'downloads', 'support'];
const pageRows = pages.map(p => {
const desktopImg = report.images.find(i => i.name === `${p}-desktop.png`);
const mobileImg = report.images.find(i => i.name === `${p}-mobile.png`);
diff --git a/e2e/pr-screenshots/documentation-dark-desktop.png b/e2e/pr-screenshots/documentation-dark-desktop.png
new file mode 100644
index 0000000..1687aab
Binary files /dev/null and b/e2e/pr-screenshots/documentation-dark-desktop.png differ
diff --git a/e2e/pr-screenshots/documentation-dark-mobile.png b/e2e/pr-screenshots/documentation-dark-mobile.png
new file mode 100644
index 0000000..8efeffd
Binary files /dev/null and b/e2e/pr-screenshots/documentation-dark-mobile.png differ
diff --git a/e2e/pr-screenshots/documentation-light-desktop.png b/e2e/pr-screenshots/documentation-light-desktop.png
new file mode 100644
index 0000000..dbf4133
Binary files /dev/null and b/e2e/pr-screenshots/documentation-light-desktop.png differ
diff --git a/e2e/pr-screenshots/documentation-light-mobile.png b/e2e/pr-screenshots/documentation-light-mobile.png
new file mode 100644
index 0000000..1add440
Binary files /dev/null and b/e2e/pr-screenshots/documentation-light-mobile.png differ
diff --git a/e2e/pr-screenshots/downloads-dark-desktop.png b/e2e/pr-screenshots/downloads-dark-desktop.png
new file mode 100644
index 0000000..4d2c97c
Binary files /dev/null and b/e2e/pr-screenshots/downloads-dark-desktop.png differ
diff --git a/e2e/pr-screenshots/downloads-dark-mobile.png b/e2e/pr-screenshots/downloads-dark-mobile.png
new file mode 100644
index 0000000..aa953e6
Binary files /dev/null and b/e2e/pr-screenshots/downloads-dark-mobile.png differ
diff --git a/e2e/pr-screenshots/downloads-light-desktop.png b/e2e/pr-screenshots/downloads-light-desktop.png
new file mode 100644
index 0000000..a5fe6c8
Binary files /dev/null and b/e2e/pr-screenshots/downloads-light-desktop.png differ
diff --git a/e2e/pr-screenshots/downloads-light-mobile.png b/e2e/pr-screenshots/downloads-light-mobile.png
new file mode 100644
index 0000000..afc55f9
Binary files /dev/null and b/e2e/pr-screenshots/downloads-light-mobile.png differ
diff --git a/e2e/pr-screenshots/home-dark-desktop.png b/e2e/pr-screenshots/home-dark-desktop.png
new file mode 100644
index 0000000..ea62a9e
Binary files /dev/null and b/e2e/pr-screenshots/home-dark-desktop.png differ
diff --git a/e2e/pr-screenshots/home-dark-mobile.png b/e2e/pr-screenshots/home-dark-mobile.png
new file mode 100644
index 0000000..80986c9
Binary files /dev/null and b/e2e/pr-screenshots/home-dark-mobile.png differ
diff --git a/e2e/pr-screenshots/home-light-desktop.png b/e2e/pr-screenshots/home-light-desktop.png
new file mode 100644
index 0000000..fec7371
Binary files /dev/null and b/e2e/pr-screenshots/home-light-desktop.png differ
diff --git a/e2e/pr-screenshots/home-light-mobile.png b/e2e/pr-screenshots/home-light-mobile.png
new file mode 100644
index 0000000..99ce6be
Binary files /dev/null and b/e2e/pr-screenshots/home-light-mobile.png differ
diff --git a/e2e/pr-screenshots/screenshots-dark-desktop.png b/e2e/pr-screenshots/screenshots-dark-desktop.png
new file mode 100644
index 0000000..010e66d
Binary files /dev/null and b/e2e/pr-screenshots/screenshots-dark-desktop.png differ
diff --git a/e2e/pr-screenshots/screenshots-dark-mobile.png b/e2e/pr-screenshots/screenshots-dark-mobile.png
new file mode 100644
index 0000000..3e55a54
Binary files /dev/null and b/e2e/pr-screenshots/screenshots-dark-mobile.png differ
diff --git a/e2e/pr-screenshots/screenshots-light-desktop.png b/e2e/pr-screenshots/screenshots-light-desktop.png
new file mode 100644
index 0000000..7ba73ba
Binary files /dev/null and b/e2e/pr-screenshots/screenshots-light-desktop.png differ
diff --git a/e2e/pr-screenshots/screenshots-light-mobile.png b/e2e/pr-screenshots/screenshots-light-mobile.png
new file mode 100644
index 0000000..63567d7
Binary files /dev/null and b/e2e/pr-screenshots/screenshots-light-mobile.png differ
diff --git a/e2e/pr-screenshots/support-dark-desktop.png b/e2e/pr-screenshots/support-dark-desktop.png
new file mode 100644
index 0000000..3a6a01c
Binary files /dev/null and b/e2e/pr-screenshots/support-dark-desktop.png differ
diff --git a/e2e/pr-screenshots/support-dark-mobile.png b/e2e/pr-screenshots/support-dark-mobile.png
new file mode 100644
index 0000000..f7b5e2d
Binary files /dev/null and b/e2e/pr-screenshots/support-dark-mobile.png differ
diff --git a/e2e/pr-screenshots/support-light-desktop.png b/e2e/pr-screenshots/support-light-desktop.png
new file mode 100644
index 0000000..1d3c1e4
Binary files /dev/null and b/e2e/pr-screenshots/support-light-desktop.png differ
diff --git a/e2e/pr-screenshots/support-light-mobile.png b/e2e/pr-screenshots/support-light-mobile.png
new file mode 100644
index 0000000..eed2b80
Binary files /dev/null and b/e2e/pr-screenshots/support-light-mobile.png differ
diff --git a/e2e/screenshots.spec.ts b/e2e/screenshots.spec.ts
index f896c1f..f070b68 100644
--- a/e2e/screenshots.spec.ts
+++ b/e2e/screenshots.spec.ts
@@ -3,13 +3,10 @@ import { expectScreenshot, printWarningSummary } from './visual';
const pages = [
{ path: '/', name: 'home' },
- { path: '/news', name: 'news' },
- { path: '/about', name: 'about' },
{ path: '/screenshots', name: 'screenshots' },
+ { path: '/documentation', name: 'documentation' },
{ path: '/downloads', name: 'downloads' },
- { path: '/quick-manual', name: 'quick-manual' },
{ path: '/support', name: 'support' },
- { path: '/license', name: 'license' },
];
const MOBILE_VIEWPORT = { width: 375, height: 812 };
@@ -38,14 +35,19 @@ test.describe('mobile screenshots', () => {
test.describe('redirects', () => {
const redirects = [
- { from: '/news.html', to: '/news' },
- { from: '/about.html', to: '/about' },
+ { from: '/news', to: '/support' },
+ { from: '/news.html', to: '/support' },
+ { from: '/about', to: '/documentation' },
+ { from: '/about.html', to: '/documentation' },
{ from: '/screenshots.html', to: '/screenshots' },
{ from: '/downloads.html', to: '/downloads' },
- { from: '/quick_manual', to: '/quick-manual' },
- { from: '/quick_manual.html', to: '/quick-manual' },
+ { from: '/quick_manual', to: '/documentation' },
+ { from: '/quick_manual.html', to: '/documentation' },
+ { from: '/quick-manual', to: '/documentation' },
+ { from: '/quick-manual.html', to: '/documentation' },
{ from: '/support.html', to: '/support' },
- { from: '/license.html', to: '/license' },
+ { from: '/license', to: '/support' },
+ { from: '/license.html', to: '/support' },
];
for (const { from, to } of redirects) {
diff --git a/e2e/screenshots/about-desktop.png b/e2e/screenshots/about-desktop.png
deleted file mode 100644
index ee44e99..0000000
Binary files a/e2e/screenshots/about-desktop.png and /dev/null differ
diff --git a/e2e/screenshots/about-mobile.png b/e2e/screenshots/about-mobile.png
deleted file mode 100644
index dbfe110..0000000
Binary files a/e2e/screenshots/about-mobile.png and /dev/null differ
diff --git a/e2e/screenshots/documentation-desktop.png b/e2e/screenshots/documentation-desktop.png
new file mode 100644
index 0000000..3c4dc60
Binary files /dev/null and b/e2e/screenshots/documentation-desktop.png differ
diff --git a/e2e/screenshots/documentation-mobile.png b/e2e/screenshots/documentation-mobile.png
new file mode 100644
index 0000000..0ecfc40
Binary files /dev/null and b/e2e/screenshots/documentation-mobile.png differ
diff --git a/e2e/screenshots/downloads-desktop.png b/e2e/screenshots/downloads-desktop.png
index c899828..7c1e600 100644
Binary files a/e2e/screenshots/downloads-desktop.png and b/e2e/screenshots/downloads-desktop.png differ
diff --git a/e2e/screenshots/downloads-mobile.png b/e2e/screenshots/downloads-mobile.png
index 2c79aa5..82d175a 100644
Binary files a/e2e/screenshots/downloads-mobile.png and b/e2e/screenshots/downloads-mobile.png differ
diff --git a/e2e/screenshots/home-desktop.png b/e2e/screenshots/home-desktop.png
index 541c551..56bcbb2 100644
Binary files a/e2e/screenshots/home-desktop.png and b/e2e/screenshots/home-desktop.png differ
diff --git a/e2e/screenshots/home-mobile.png b/e2e/screenshots/home-mobile.png
index 6965277..5a6c767 100644
Binary files a/e2e/screenshots/home-mobile.png and b/e2e/screenshots/home-mobile.png differ
diff --git a/e2e/screenshots/license-desktop.png b/e2e/screenshots/license-desktop.png
deleted file mode 100644
index fecf276..0000000
Binary files a/e2e/screenshots/license-desktop.png and /dev/null differ
diff --git a/e2e/screenshots/license-mobile.png b/e2e/screenshots/license-mobile.png
deleted file mode 100644
index f66be7f..0000000
Binary files a/e2e/screenshots/license-mobile.png and /dev/null differ
diff --git a/e2e/screenshots/news-desktop.png b/e2e/screenshots/news-desktop.png
deleted file mode 100644
index bbc654c..0000000
Binary files a/e2e/screenshots/news-desktop.png and /dev/null differ
diff --git a/e2e/screenshots/news-mobile.png b/e2e/screenshots/news-mobile.png
deleted file mode 100644
index 09a5ab9..0000000
Binary files a/e2e/screenshots/news-mobile.png and /dev/null differ
diff --git a/e2e/screenshots/quick-manual-desktop.png b/e2e/screenshots/quick-manual-desktop.png
deleted file mode 100644
index 9ed6dd1..0000000
Binary files a/e2e/screenshots/quick-manual-desktop.png and /dev/null differ
diff --git a/e2e/screenshots/quick-manual-mobile.png b/e2e/screenshots/quick-manual-mobile.png
deleted file mode 100644
index 86965ff..0000000
Binary files a/e2e/screenshots/quick-manual-mobile.png and /dev/null differ
diff --git a/e2e/screenshots/screenshots-desktop.png b/e2e/screenshots/screenshots-desktop.png
index 24fe1fa..e564df0 100644
Binary files a/e2e/screenshots/screenshots-desktop.png and b/e2e/screenshots/screenshots-desktop.png differ
diff --git a/e2e/screenshots/screenshots-mobile.png b/e2e/screenshots/screenshots-mobile.png
index c7d2354..59445c9 100644
Binary files a/e2e/screenshots/screenshots-mobile.png and b/e2e/screenshots/screenshots-mobile.png differ
diff --git a/e2e/screenshots/support-desktop.png b/e2e/screenshots/support-desktop.png
index 417fbe7..fc07156 100644
Binary files a/e2e/screenshots/support-desktop.png and b/e2e/screenshots/support-desktop.png differ
diff --git a/e2e/screenshots/support-mobile.png b/e2e/screenshots/support-mobile.png
index dc21d43..4adb3c6 100644
Binary files a/e2e/screenshots/support-mobile.png and b/e2e/screenshots/support-mobile.png differ
diff --git a/eslint.config.mjs b/eslint.config.mjs
index bb2613e..d9b9a92 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -13,7 +13,6 @@ const eslintConfig = [
...compat.extends('next/core-web-vitals', 'next/typescript', 'prettier'),
{
rules: {
- 'react/jsx-no-target-blank': 'off',
'prefer-const': 'error',
},
},
diff --git a/package.json b/package.json
index 59c27b0..d2605bc 100644
--- a/package.json
+++ b/package.json
@@ -7,9 +7,9 @@
"author": {
"name": "Volodymyr Vreshch",
"email": "vreshch@gmail.com",
- "url": "http://vreshch.com"
+ "url": "https://vreshch.com"
},
- "homepage": "http://diffractwd.com",
+ "homepage": "https://diffractwd.com",
"repository": {
"type": "git",
"url": "git+https://github.com/vreshch/diffractwd.com.git"
@@ -29,7 +29,8 @@
"test:unit": "vitest run",
"test:watch": "vitest",
"test:e2e": "npx playwright test",
- "test:e2e:ui": "npx playwright test --ui"
+ "test:e2e:ui": "npx playwright test --ui",
+ "verify": "npx tsc --noEmit && next lint && npm run build && vitest run"
},
"dependencies": {
"clsx": "^2.1.1",
diff --git a/public/hero.jpg b/public/hero.jpg
new file mode 100644
index 0000000..927924b
Binary files /dev/null and b/public/hero.jpg differ
diff --git a/public/screenshots/screenshot1_mini.jpg b/public/screenshots/screenshot1_mini.jpg
index fddc989..81d041b 100644
Binary files a/public/screenshots/screenshot1_mini.jpg and b/public/screenshots/screenshot1_mini.jpg differ
diff --git a/public/screenshots/screenshot2_mini.jpg b/public/screenshots/screenshot2_mini.jpg
index 0ffe885..b040307 100644
Binary files a/public/screenshots/screenshot2_mini.jpg and b/public/screenshots/screenshot2_mini.jpg differ
diff --git a/public/screenshots/screenshot3_mini.jpg b/public/screenshots/screenshot3_mini.jpg
index 2e578a1..b192473 100644
Binary files a/public/screenshots/screenshot3_mini.jpg and b/public/screenshots/screenshot3_mini.jpg differ
diff --git a/public/screenshots/screenshot4_mini.jpg b/public/screenshots/screenshot4_mini.jpg
index dc39a4c..05e0ea6 100644
Binary files a/public/screenshots/screenshot4_mini.jpg and b/public/screenshots/screenshot4_mini.jpg differ
diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx
deleted file mode 100644
index 63ce294..0000000
--- a/src/app/about/page.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import type { Metadata } from 'next';
-import Link from 'next/link';
-
-export const metadata: Metadata = {
- title: 'DiffractWD - About',
-};
-
-export default function AboutPage() {
- return (
-
-
About
-
-
-
- Supporting file formats
-
- Powder Pattern Import: Bruker/Siemens RAW Files
- (*.raw), Philips RD Files (*.rd), Scintag ARD Files (*.ard), Sietronics CPI Files
- (*.cpi), Riet7 DAT Files (*.dat), DBW Files (*.dbw), GSAS Files (*.gsas), Jade MDI Files
- (*.mdi), Rigaku RIG Files (*.rig), Philips UDF Files(*.udf), UXD Files (*.uxd), XDA
- Files (*.xda), XDD Files (*.xdd), XY Files (*.xy)
-
-
- Molecule Import: ShelX File (*.ins,*.res),
- Crystallography Information File (*.cif)
-
-
-
- Main functions
- + Multiple Powder Pattern and Molecule Import
- + Symulation of Powder Patterns based on single crystal data
- + Background subtraction, Smoth, and Scale of Powder Patterns
- + Working area properties change (Grids, Tics, Axis Labels,..)
- + Graph properties change (Color,...)
- + Picture export to *.wmf
- + Auto Update and Error Report modules
-
-
- System requirements
- Windows XP, Vista, Windows 7
- Microsoft .NET Framework 2.0 need to be installed
-
-
- Technical details
- Program Written in C#, pure object orientated language.
-
- Core is base on Sharp Develop, which were proved can be easily scale up.
-
- Program can be easily extended through Addin system.
-
- Licensed under terms of
-
- BSD License.
-
-
-
-
- Modules included
- ICSharpCode.Core (Sharp Develop Application Core)
- ICSharpCode.AddInManager (Sharp Develop AddInManager)
- ICSharpCode.SharpZipLib,Ionic.Zip (Zip support Library)
- log4net (Log support)
- PowDLL (Powder Pattern Import)
- WeifenLuo.WinFormsUI.Docking (Advanced Windows Docking)
- ZedGraph (Graph Functionality)
-
-
-
- );
-}
diff --git a/src/app/documentation/page.tsx b/src/app/documentation/page.tsx
new file mode 100644
index 0000000..64a8f49
--- /dev/null
+++ b/src/app/documentation/page.tsx
@@ -0,0 +1,366 @@
+import type { Metadata } from 'next';
+import Image from 'next/image';
+
+export const metadata: Metadata = {
+ title: 'DiffractWD - Documentation',
+};
+
+const steps = [
+ {
+ number: 1,
+ title: 'Import your files',
+ description:
+ 'Import powder patterns and crystal structures. Supported formats: *.raw, *.rd, *.ard, *.cpi, *.dat, *.dbw, *.gsas, *.mdi, *.rig, *.udf, *.uxd, *.xda, *.xdd, *.xy, ShelX (*.ins, *.res), CIF (*.cif).',
+ image: '/manual/help1.jpg',
+ },
+ {
+ number: 2,
+ title: 'Adjust visibility',
+ description:
+ 'Change visibility of patterns and perform all necessary comparisons between experimental and simulated data.',
+ image: '/manual/help2.jpg',
+ },
+ {
+ number: 3,
+ title: 'Customize properties',
+ description:
+ 'Fine-tune 2-theta range, FWHM of profiles, and curve colors. Adjust grids, axis labels, and work area properties.',
+ image: '/manual/help3.jpg',
+ },
+ {
+ number: 4,
+ title: 'Export your results',
+ description:
+ 'Copy the image to clipboard or export to WMF format for publication-quality figures.',
+ image: '/manual/help4.jpg',
+ },
+];
+
+const fileFormats = [
+ {
+ category: 'Powder Patterns',
+ formats: 'RAW, RD, ARD, CPI, DAT, DBW, GSAS, MDI, RIG, UDF, UXD, XDA, XDD, XY',
+ },
+ { category: 'Crystal Structures', formats: 'ShelX (INS, RES), CIF' },
+];
+
+const capabilities = [
+ {
+ text: 'Multiple powder pattern and molecule import',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ text: 'Powder pattern simulation from single crystal data',
+ icon: (
+
+
+
+ ),
+ },
+ {
+ text: 'Background subtraction, smoothing, and scaling',
+ icon: (
+
+
+
+
+
+
+
+ ),
+ },
+ {
+ text: 'Customizable work area (grids, tics, axis labels)',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ text: 'Graph color and style customization',
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ text: 'Image export to WMF format',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ text: 'Auto-update and error reporting',
+ icon: (
+
+
+
+
+ ),
+ },
+];
+
+const modules = [
+ { name: 'ICSharpCode.Core', description: 'Application core framework' },
+ { name: 'ICSharpCode.AddInManager', description: 'Add-in management' },
+ { name: 'ICSharpCode.SharpZipLib', description: 'Archive support' },
+ { name: 'log4net', description: 'Logging' },
+ { name: 'PowDLL', description: 'Powder pattern import' },
+ { name: 'WeifenLuo.WinFormsUI.Docking', description: 'Window docking' },
+ { name: 'ZedGraph', description: 'Graph rendering' },
+];
+
+export default function DocumentationPage() {
+ return (
+
+
+
+
Documentation
+
+ Learn how to use DiffractWD for powder diffraction analysis.
+
+
+
+
+
+
+ {/* Quick Start */}
+
+
+
+ {steps.map((step) => (
+
+
+
+
+
+
+
+ Step {step.number}
+
+
+ {step.title}
+
+
+
+ {step.description}
+
+
+
+ ))}
+
+
+
+ {/* File Formats */}
+
+
+
+
+ Supported File Formats
+
+
+
+
+
+
+
+ Category
+
+
+ Formats
+
+
+
+
+ {fileFormats.map((row) => (
+
+
+ {row.category}
+
+
+ {row.formats}
+
+
+ ))}
+
+
+
+
+
+ {/* Capabilities */}
+
+
+
+ {capabilities.map((cap) => (
+
+
+ {cap.icon}
+
+
{cap.text}
+
+ ))}
+
+
+
+ {/* System & Technical */}
+
+
+
+
+
+
+
+
+
+
+ System Requirements
+
+
+
+
+
+ •
+ Windows XP, Vista, or Windows 7
+
+
+ •
+ Microsoft .NET Framework 2.0
+
+
+
+
+
+
+
+
+
+ Technical Details
+
+
+
+
+
+ •
+ Written in C# (object-oriented)
+
+
+ •
+ Built on SharpDevelop application core
+
+
+ •
+ Extensible through add-in system
+
+
+ •
+ MIT License
+
+
+
+
+
+
+ {/* Modules */}
+
+
+
+
+ Included Modules
+
+
+
+
+
+
+
+ Module
+
+
+ Purpose
+
+
+
+
+ {modules.map((mod) => (
+
+
+ {mod.name}
+
+
+ {mod.description}
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/downloads/page.tsx b/src/app/downloads/page.tsx
index c3c96fa..957f34d 100644
--- a/src/app/downloads/page.tsx
+++ b/src/app/downloads/page.tsx
@@ -1,82 +1,146 @@
import type { Metadata } from 'next';
-import Image from 'next/image';
import Link from 'next/link';
export const metadata: Metadata = {
title: 'DiffractWD - Downloads',
};
+const downloads = [
+ {
+ title: 'Installation Program',
+ description: 'Recommended. Includes installer with all dependencies.',
+ href: '/downloads/diffractwd.exe',
+ type: 'EXE',
+ recommended: true,
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ title: 'Compressed Binaries',
+ description: 'Portable version. Extract and run without installation.',
+ href: '/downloads/diffractwd_bin.zip',
+ type: 'ZIP',
+ recommended: false,
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ title: 'Source Code',
+ description: 'Full C# source code. Build with Visual Studio or SharpDevelop.',
+ href: '/downloads/diffractwd_src.zip',
+ type: 'ZIP',
+ recommended: false,
+ icon: (
+
+
+
+
+ ),
+ },
+];
+
export default function DownloadsPage() {
return (
-
Downloads
-
-
-
- DiffractWD 1.30
-
-
-
-
- Installation program
-
+
+
+
+
+ Latest stable release
+
+
Downloads
+
+ DiffractWD v1.30 — choose the package that works best for you.
+
+
+
+
+
+
+
);
diff --git a/src/app/globals.css b/src/app/globals.css
index 3b394ea..fb6f9b3 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -2,25 +2,45 @@
@source "../**/*.{ts,tsx}";
+@custom-variant dark (&:where(.dark, .dark *));
+
@theme {
- --color-primary: #2b6892;
- --color-primary-light: #4a97cc;
- --color-heading: #182c60;
- --color-sidebar-hover: #f5f5f5;
- --color-sidebar-border: #0275d8;
- --color-subtitle: #373a3c;
+ --color-primary: #1e3a5f;
+ --color-primary-light: #2b6892;
+ --color-accent: #2563eb;
+ --color-accent-light: #60a5fa;
+ --color-surface: #eef2f7;
+ --color-surface-alt: #e3e9f1;
+ --color-surface-hover: #dce3ed;
+ --color-heading: #1e3a5f;
+ --color-body: #374a60;
+ --color-muted: #5a6d82;
+ --color-border: #c2cdd9;
+ --color-dark-bg: #0f172a;
+ --color-dark-surface: #1e293b;
+ --color-dark-surface-alt: #334155;
+ --color-dark-text: #f1f5f9;
+ --color-dark-text-secondary: #94a3b8;
+ --color-dark-border: #334155;
}
* {
box-sizing: border-box;
}
-html,
+html {
+ scroll-behavior: smooth;
+}
+
+html {
+ overflow-y: scroll;
+}
+
body {
padding: 0;
margin: 0;
- overflow-y: scroll;
font-family:
+ Inter,
-apple-system,
BlinkMacSystemFont,
Segoe UI,
@@ -32,6 +52,14 @@ body {
Droid Sans,
Helvetica Neue,
sans-serif;
+ color: var(--color-body);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.dark body {
+ color: var(--color-dark-text);
+ background-color: var(--color-dark-bg);
}
a {
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 1800d3c..dcd0290 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,5 +1,5 @@
import type { Metadata } from 'next';
-import { Sidebar } from '@/components/sidebar';
+import { Navigation } from '@/components/navigation';
import './globals.css';
export const metadata: Metadata = {
@@ -12,29 +12,33 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
-
-
-
-
-
-
-
Diffract WD
-
- :: by Vreshch ::
-
-
-
-
-
- © Vreshch V.D. {new Date().getFullYear()}
-
+
+
+
+
+
+
+
{children}
+
+
);
diff --git a/src/app/license/page.tsx b/src/app/license/page.tsx
deleted file mode 100644
index 8f0f992..0000000
--- a/src/app/license/page.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import type { Metadata } from 'next';
-
-export const metadata: Metadata = {
- title: 'DiffractWD - BSD LICENSE',
-};
-
-export default function LicensePage() {
- return (
-
-
BSD 2 License
-
-
-
Copyright {new Date().getFullYear()} @Vreshch V.D.
-
- Redistribution and use in source and binary forms, with or without modification, are
- permitted provided that the following conditions are met:
-
-
- 1. Redistributions of source code must retain the above copyright notice, this list of
- conditions and the following disclaimer.
-
-
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of
- conditions and the following disclaimer in the documentation and/or other materials
- provided with the distribution.
-
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
- );
-}
diff --git a/src/app/news/page.tsx b/src/app/news/page.tsx
deleted file mode 100644
index ac0ae37..0000000
--- a/src/app/news/page.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import type { Metadata } from 'next';
-
-export const metadata: Metadata = {
- title: 'DiffractWD - News',
-};
-
-export default function NewsPage() {
- return (
-
-
News
-
-
-
- Website updated (17-October-2021)
- Website core moved to TypeScript,NextJS
-
-
- Website updated (17-October-2016)
- Website core moved to React&MongoDB
-
-
- Version 1.30 (28-January-2011)
-
- Article is available : (
-
- V.D. Vreshch J. App. Cryst. ,44, 219-220 2011
-
- )
-
- Windows Vista and Windows 7 support
- New webpage design
- Bug fix
-
-
- Version 1.20 (27-October-2010)
- Background subtracts, Smooth, and Scale function added
- Graph navigation improve
- Revision of Powder Pattern generation module
- Help menu added
- Image export
- Bug fix
-
-
- Version 1.02 (16-June-2010)
- Installation Package Available
- Several Bug Fixed
- Native File Format Support
- Several Menu Items Added (Help)
-
-
- Version 1.01 (6-June-2010)
- Precompiled package available
- Source code (C#) available for download
-
-
- Version 1.00 (15-May-2010)
- Program was distributed among limited number of users.
- Several bug fixed
-
-
-
- );
-}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 89d92d7..09e76bb 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,57 +1,252 @@
import type { Metadata } from 'next';
import Image from 'next/image';
+import Link from 'next/link';
export const metadata: Metadata = {
- title: 'DiffractWD - Overview',
+ title: 'DiffractWD - Free Powder Diffraction Software',
};
+const features = [
+ {
+ title: 'Multiple Format Support',
+ description:
+ 'Import powder patterns from 14 file formats including RAW, RD, CPI, UXD, XY, and more. Load crystal structures from CIF and ShelX files.',
+ icon: (
+
+
+
+
+
+
+ ),
+ },
+ {
+ title: 'Pattern Simulation',
+ description:
+ 'Simulate powder patterns from single crystal data. Compare experimental and calculated patterns side by side.',
+ icon: (
+
+
+
+ ),
+ },
+ {
+ title: 'Data Processing',
+ description:
+ 'Background subtraction, smoothing, and scaling. Customize 2-theta range, FWHM, and curve colors.',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ title: 'Publication Ready',
+ description:
+ 'Export graphs as WMF images. Customize grids, axis labels, and graph colors for publication-quality figures.',
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ title: 'Open Source',
+ description:
+ 'Written in C# with an extensible add-in system. Licensed under the MIT License. Free to use and modify.',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ title: 'Auto Updates',
+ description:
+ 'Built-in auto-update and error reporting modules keep you on the latest stable version.',
+ icon: (
+
+
+
+
+ ),
+ },
+];
+
+const stats = [
+ { value: '14+', label: 'File Formats' },
+ { value: 'CIF', label: 'Crystal Structures' },
+ { value: 'WMF', label: 'Export Format' },
+ { value: 'MIT', label: 'License' },
+];
+
export default function HomePage() {
return (
-
Overview
-
-
-
- DiffractWD is a tool to easily manipulate with Powder Patterns, both experimental
- and simulated. The user interface is designed to be simple and user-friendly, and do not
- require any crystallographic background. With just a few clicks - you can compare measured
- patterns, and prepare picture for publication.
-
-
-
-
-
-
+ {/* Hero */}
+
+
+
+
+
+
+
+ Free & Open Source
+
+
+ DiffractWD
+
+
+ Powder diffraction analysis made simple.
+
+
+ Compare measured patterns, simulate from crystal data, and prepare
+ publication-ready figures — no crystallographic background required.
+
+
+
+
+
+
-
- Source Code of DiffractWD is open for public, and build based on Extendable
- system. The system provide developers with interfaces to build their own addin's, and
- extend minimal functions.
-
+ {/* Stats bar */}
+
+
+ {stats.map((stat) => (
+
+
+ {stat.value}
+
+
+ {stat.label}
+
+
+ ))}
+
+
-
- Please note, DiffractWD is far from complete. Program contain Autoupdate and Error Report
- modules - and will let you to have the latest stable version installed. There are
- many missing features that are planned for future versions.
-
+ {/* Features */}
+
+
+
+
+ Everything you need
+
+
+ A complete toolkit for powder diffraction pattern analysis, simulation, and
+ visualization.
+
+
+
+ {features.map((feature) => (
+
+
+ {feature.icon}
+
+
+ {feature.title}
+
+
+ {feature.description}
+
+
+ ))}
+
+
+
-
-
+
+
+ {/* CTA */}
+
+
+
+ Ready to get started?
+
+
+ Windows XP, Vista, or Windows 7. Requires .NET Framework 2.0.
+
+
+
+
);
}
diff --git a/src/app/quick-manual/page.tsx b/src/app/quick-manual/page.tsx
deleted file mode 100644
index 96330bd..0000000
--- a/src/app/quick-manual/page.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import type { Metadata } from 'next';
-import Image from 'next/image';
-
-export const metadata: Metadata = {
- title: 'DiffractWD - Quick Manual',
-};
-
-export default function QuickManualPage() {
- return (
-
-
Quick Manual
-
-
-
-
-
-
-
-
Step 1
-
- Import all necessary files.
-
- Supported Powder Pattern File formats: *.raw, *.rd,*.ard, *.cpi, *.dat, *.dbw,
- *.gsas, *.mdi, *.rig, *.udf, *.uxd, *.xda, *.xdd, *.xy
-
- Molecule Import: ShelX File (*.ins,*.res), Crystallography Information File
- (*.cif)
-
-
-
-
-
-
-
-
-
-
Step 2
-
Change visibility and perform all necessary conclusions
-
-
-
-
-
-
-
-
-
Step 3
-
- If necessary : change properties
- - 2 Theta range, FWHM of profiles, Curves color
-
-
-
-
-
-
-
-
-
-
Step 4
-
Copy image to clipboard
-
-
-
-
- );
-}
diff --git a/src/app/screenshots/page.tsx b/src/app/screenshots/page.tsx
index 701f4af..a6207a1 100644
--- a/src/app/screenshots/page.tsx
+++ b/src/app/screenshots/page.tsx
@@ -1,73 +1,47 @@
import type { Metadata } from 'next';
-import Image from 'next/image';
+import { ScreenshotGallery } from '@/components/lightbox';
export const metadata: Metadata = {
title: 'DiffractWD - Screenshots',
};
+const screenshots = [
+ {
+ src: '/screenshots/screenshot1_mini.jpg',
+ full: '/screenshots/screenshot1.jpg',
+ title: 'Default Open Window',
+ },
+ {
+ src: '/screenshots/screenshot2_mini.jpg',
+ full: '/screenshots/screenshot2.jpg',
+ title: 'Powder Pattern Import',
+ },
+ {
+ src: '/screenshots/screenshot3_mini.jpg',
+ full: '/screenshots/screenshot3.jpg',
+ title: 'Powder Pattern Simulation',
+ },
+ {
+ src: '/screenshots/screenshot4_mini.jpg',
+ full: '/screenshots/screenshot4.jpg',
+ title: 'Advanced Windows Docking',
+ },
+];
+
export default function ScreenshotsPage() {
return (
-
Screenshots
-
-
-
-
-
-
-
-
Default Open Window
-
-
-
-
-
-
Powder Pattern Import
-
-
-
-
-
-
-
-
-
Powder Pattern Simulation
-
-
-
-
-
-
Advanced Windows Docking
-
+
+
+
Screenshots
+
+ See DiffractWD in action. Click any image to view full size.
+
+
+
+
+
);
diff --git a/src/app/support/page.tsx b/src/app/support/page.tsx
index 1944fb0..e0d8efd 100644
--- a/src/app/support/page.tsx
+++ b/src/app/support/page.tsx
@@ -4,29 +4,213 @@ export const metadata: Metadata = {
title: 'DiffractWD - Support',
};
+const changelog = [
+ {
+ version: '2.0',
+ date: 'March 2025',
+ changes: [
+ 'Website redesigned with modern layout and dark mode',
+ 'Consolidated pages for improved navigation',
+ 'Responsive design for mobile and desktop',
+ ],
+ },
+ {
+ version: '1.30',
+ date: '28 January 2011',
+ changes: [
+ 'Published: V.D. Vreshch, J. App. Cryst., 44, 219-220 (2011)',
+ 'Windows Vista and Windows 7 support',
+ 'New webpage design',
+ 'Bug fixes',
+ ],
+ },
+ {
+ version: '1.20',
+ date: '27 October 2010',
+ changes: [
+ 'Background subtraction, smoothing, and scale functions',
+ 'Graph navigation improvements',
+ 'Powder pattern generation module revision',
+ 'Help menu and image export added',
+ 'Bug fixes',
+ ],
+ },
+ {
+ version: '1.02',
+ date: '16 June 2010',
+ changes: [
+ 'Installation package available',
+ 'Native file format support',
+ 'Several bug fixes',
+ ],
+ },
+ {
+ version: '1.01',
+ date: '6 June 2010',
+ changes: [
+ 'Precompiled package available',
+ 'Source code (C#) available for download',
+ ],
+ },
+ {
+ version: '1.00',
+ date: '15 May 2010',
+ changes: ['Initial release to limited number of users'],
+ },
+];
+
export default function SupportPage() {
return (
-
Support
-
-
-
- Author
-
-
- Volodymyr D. Vreshch
+
+
+
Support
+
+ Get help, report issues, or review the license.
+
+
+
+
+
+
+ {/* Author & Feedback */}
+
+
+
+
+
+ Volodymyr D. Vreshch
-
-
-
- Feedback
- Feel free if you have:
- + Suggestions
- + Bug Reports
- + Future requests
- + Need Help
- Your feedback is very important to us
-
+
+
+ Ph.D. in Inorganic Chemistry, Kyiv, Ukraine
+
+
+ Senior Software Engineer at Microsoft
+
+
+
+
+
We welcome your input:
+
+
+ •
+ Suggestions and feature requests
+
+
+ •
+ Bug reports
+
+
+ •
+ Questions and help requests
+
+
+
+
+
+ {/* Changelog */}
+
+
+
+ {/* Timeline line */}
+
+ {changelog.map((release, idx) => (
+
+ {/* Timeline dot */}
+
+
+
+
+ v{release.version}
+
+
+ {release.date}
+
+
+
+ {release.changes.map((change, i) => (
+
+
+ {change}
+
+ ))}
+
+
+
+ ))}
+
+
+
+ {/* License */}
+
+
+
+
+ Copyright {new Date().getFullYear()} Volodymyr D. Vreshch
+
+
+ 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:
+
+
+ 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.
+
+
+
);
diff --git a/src/components/lightbox.tsx b/src/components/lightbox.tsx
new file mode 100644
index 0000000..5d51b1d
--- /dev/null
+++ b/src/components/lightbox.tsx
@@ -0,0 +1,81 @@
+'use client';
+
+import { useState, useCallback, useEffect } from 'react';
+import Image from 'next/image';
+
+interface LightboxImage {
+ src: string;
+ full: string;
+ title: string;
+}
+
+export function ScreenshotGallery({ screenshots }: { screenshots: LightboxImage[] }) {
+ const [activeIndex, setActiveIndex] = useState
(null);
+
+ const close = useCallback(() => setActiveIndex(null), []);
+
+ useEffect(() => {
+ if (activeIndex === null) return;
+ document.body.style.overflow = 'hidden';
+ const handleKey = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') close();
+ };
+ document.addEventListener('keydown', handleKey);
+ return () => {
+ document.body.style.overflow = '';
+ document.removeEventListener('keydown', handleKey);
+ };
+ }, [activeIndex, close]);
+
+ return (
+ <>
+
+ {screenshots.map((shot, i) => (
+
setActiveIndex(i)}
+ className="group relative cursor-zoom-in text-left"
+ >
+
+
+
+
+
+
+ ))}
+
+
+ {activeIndex !== null && (
+
+
+ ×
+
+
+
+ )}
+ >
+ );
+}
diff --git a/src/components/navigation.test.tsx b/src/components/navigation.test.tsx
new file mode 100644
index 0000000..1e3f8e8
--- /dev/null
+++ b/src/components/navigation.test.tsx
@@ -0,0 +1,77 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import { Navigation } from './navigation';
+import { navItems } from '@/lib/constants';
+
+vi.mock('next/link', () => ({
+ default: ({
+ children,
+ href,
+ className,
+ onClick,
+ }: {
+ children: React.ReactNode;
+ href: string;
+ className?: string;
+ onClick?: () => void;
+ }) => (
+
+ {children}
+
+ ),
+}));
+
+vi.mock('next/navigation', () => ({
+ usePathname: () => '/',
+}));
+
+describe('Navigation', () => {
+ it('renders all navigation items', () => {
+ render( );
+
+ for (const item of navItems) {
+ const links = screen.getAllByText(item.label);
+ expect(links.length).toBeGreaterThan(0);
+ }
+ });
+
+ it('renders navigation links with correct hrefs', () => {
+ render( );
+
+ for (const item of navItems) {
+ const links = screen.getAllByText(item.label);
+ expect(links[0].closest('a')).toHaveAttribute('href', item.href);
+ }
+ });
+
+ it('renders the mobile menu toggle button', () => {
+ render( );
+
+ const button = screen.getByLabelText('Toggle menu');
+ expect(button).toBeInTheDocument();
+ });
+
+ it('renders the theme toggle button', () => {
+ render( );
+
+ const buttons = screen.getAllByLabelText('Toggle theme');
+ expect(buttons.length).toBeGreaterThan(0);
+ });
+
+ it('toggles mobile menu on button click', () => {
+ render( );
+
+ const button = screen.getByLabelText('Toggle menu');
+ fireEvent.click(button);
+
+ const header = button.closest('header');
+ expect(header).toBeInTheDocument();
+ });
+
+ it('renders the site title link', () => {
+ render( );
+
+ const titlePart = screen.getByText('WD');
+ expect(titlePart.closest('a')).toHaveAttribute('href', '/');
+ });
+});
diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx
new file mode 100644
index 0000000..3e1e652
--- /dev/null
+++ b/src/components/navigation.tsx
@@ -0,0 +1,141 @@
+'use client';
+
+import { useState, useEffect } from 'react';
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { cn } from '@/lib/cn';
+import { navItems } from '@/lib/constants';
+import { ThemeToggle } from '@/components/theme-toggle';
+
+export function Navigation() {
+ const [mobileOpen, setMobileOpen] = useState(false);
+ const [scrolled, setScrolled] = useState(false);
+ const pathname = usePathname();
+
+ useEffect(() => {
+ const onScroll = () => setScrolled(window.scrollY > 16);
+ onScroll();
+ window.addEventListener('scroll', onScroll, { passive: true });
+ return () => window.removeEventListener('scroll', onScroll);
+ }, []);
+
+ useEffect(() => {
+ setMobileOpen(false);
+ }, [pathname]);
+
+ return (
+
+ );
+}
diff --git a/src/components/sidebar.test.tsx b/src/components/sidebar.test.tsx
deleted file mode 100644
index 56ef009..0000000
--- a/src/components/sidebar.test.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import { describe, it, expect, vi } from 'vitest';
-import { render, screen, fireEvent } from '@testing-library/react';
-import { Sidebar } from './sidebar';
-import { navItems } from '@/lib/constants';
-
-vi.mock('next/link', () => ({
- default: ({
- children,
- href,
- className,
- }: {
- children: React.ReactNode;
- href: string;
- className?: string;
- }) => (
-
- {children}
-
- ),
-}));
-
-vi.mock('next/navigation', () => ({
- usePathname: () => '/',
-}));
-
-describe('Sidebar', () => {
- it('renders all navigation items', () => {
- render( );
-
- for (const item of navItems) {
- expect(screen.getByText(item.label)).toBeInTheDocument();
- }
- });
-
- it('renders navigation links with correct hrefs', () => {
- render( );
-
- for (const item of navItems) {
- const link = screen.getByText(item.label);
- expect(link.closest('a')).toHaveAttribute('href', item.href);
- }
- });
-
- it('renders the mobile menu toggle button', () => {
- render( );
-
- const button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
- });
-
- it('toggles mobile menu on button click', () => {
- render( );
-
- const button = screen.getByRole('button');
-
- fireEvent.click(button);
-
- const nav = button.closest('nav');
- expect(nav).toBeInTheDocument();
- });
-
- it('highlights the active route', () => {
- render( );
-
- const homeLink = screen.getByText('Home').closest('a');
- expect(homeLink?.className).toContain('font-semibold');
- });
-
- it('does not highlight non-active routes', () => {
- render( );
-
- const newsLink = screen.getByText('News').closest('a');
- expect(newsLink?.className).not.toContain('font-semibold');
- });
-});
diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx
deleted file mode 100644
index 66d4159..0000000
--- a/src/components/sidebar.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-'use client';
-
-import { useState } from 'react';
-import Link from 'next/link';
-import { usePathname } from 'next/navigation';
-import { cn } from '@/lib/cn';
-import { navItems } from '@/lib/constants';
-
-export function Sidebar() {
- const [closed, setClosed] = useState(true);
- const pathname = usePathname();
-
- return (
-
-
- setClosed(!closed)}
- >
- ☰
-
-
-
- {navItems.map(({ href, label }) => (
-
- {label}
-
- ))}
-
-
- );
-}
diff --git a/src/components/theme-toggle.tsx b/src/components/theme-toggle.tsx
new file mode 100644
index 0000000..70fbdf0
--- /dev/null
+++ b/src/components/theme-toggle.tsx
@@ -0,0 +1,72 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { cn } from '@/lib/cn';
+
+export function ThemeToggle() {
+ const [dark, setDark] = useState(false);
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+ const stored = localStorage.getItem('theme');
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ const isDark = stored === 'dark' || (!stored && prefersDark);
+ setDark(isDark);
+ document.documentElement.classList.toggle('dark', isDark);
+ }, []);
+
+ const toggle = () => {
+ const next = !dark;
+ setDark(next);
+ document.documentElement.classList.toggle('dark', next);
+ localStorage.setItem('theme', next ? 'dark' : 'light');
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/src/lib/constants.test.ts b/src/lib/constants.test.ts
index 94c8241..ee61278 100644
--- a/src/lib/constants.test.ts
+++ b/src/lib/constants.test.ts
@@ -13,11 +13,9 @@ describe('navItems', () => {
it('includes all main pages', () => {
const labels = navItems.map((item) => item.label);
expect(labels).toContain('Home');
- expect(labels).toContain('News');
- expect(labels).toContain('About');
expect(labels).toContain('Screenshots');
+ expect(labels).toContain('Documentation');
expect(labels).toContain('Downloads');
- expect(labels).toContain('Quick Manual');
expect(labels).toContain('Support');
});
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index a0e82d6..4032564 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -5,11 +5,9 @@ export interface NavItem {
export const navItems: NavItem[] = [
{ href: '/', label: 'Home' },
- { href: '/news', label: 'News' },
- { href: '/about', label: 'About' },
{ href: '/screenshots', label: 'Screenshots' },
+ { href: '/documentation', label: 'Documentation' },
{ href: '/downloads', label: 'Downloads' },
- { href: '/quick-manual', label: 'Quick Manual' },
{ href: '/support', label: 'Support' },
];
diff --git a/src/lib/redirects.test.ts b/src/lib/redirects.test.ts
index b8538a3..4eb2bd6 100644
--- a/src/lib/redirects.test.ts
+++ b/src/lib/redirects.test.ts
@@ -22,7 +22,7 @@ describe('redirects', () => {
}
});
- it('maps legacy underscore URLs to kebab-case', () => {
+ it('maps legacy underscore URLs to new paths', () => {
const underscoreRedirects = redirects.filter((r) => r.source.includes('_'));
expect(underscoreRedirects.length).toBeGreaterThanOrEqual(1);
@@ -31,13 +31,18 @@ describe('redirects', () => {
}
});
- it('redirects quick_manual to quick-manual', () => {
- const quickManualRedirects = redirects.filter((r) => r.destination === '/quick-manual');
- expect(quickManualRedirects.length).toBe(2);
+ it('redirects old pages to new consolidated pages', () => {
+ const newsRedirects = redirects.filter((r) => r.source.includes('news'));
+ expect(newsRedirects.every((r) => r.destination === '/support')).toBe(true);
- const sources = quickManualRedirects.map((r) => r.source);
- expect(sources).toContain('/quick_manual');
- expect(sources).toContain('/quick_manual.html');
+ const aboutRedirects = redirects.filter((r) => r.source.includes('about'));
+ expect(aboutRedirects.every((r) => r.destination === '/documentation')).toBe(true);
+
+ const manualRedirects = redirects.filter((r) => r.source.includes('manual'));
+ expect(manualRedirects.every((r) => r.destination === '/documentation')).toBe(true);
+
+ const licenseRedirects = redirects.filter((r) => r.source.includes('license'));
+ expect(licenseRedirects.every((r) => r.destination === '/support')).toBe(true);
});
it('has unique source paths', () => {
diff --git a/src/lib/redirects.ts b/src/lib/redirects.ts
index 3917ae4..6449794 100644
--- a/src/lib/redirects.ts
+++ b/src/lib/redirects.ts
@@ -5,12 +5,17 @@ export interface Redirect {
}
export const redirects: Redirect[] = [
- { source: '/news.html', destination: '/news', permanent: true },
- { source: '/about.html', destination: '/about', permanent: true },
+ { source: '/news.html', destination: '/support', permanent: true },
+ { source: '/news', destination: '/support', permanent: true },
+ { source: '/about.html', destination: '/documentation', permanent: true },
+ { source: '/about', destination: '/documentation', permanent: true },
{ source: '/screenshots.html', destination: '/screenshots', permanent: true },
{ source: '/downloads.html', destination: '/downloads', permanent: true },
- { source: '/quick_manual.html', destination: '/quick-manual', permanent: true },
- { source: '/quick_manual', destination: '/quick-manual', permanent: true },
+ { source: '/quick_manual.html', destination: '/documentation', permanent: true },
+ { source: '/quick_manual', destination: '/documentation', permanent: true },
+ { source: '/quick-manual.html', destination: '/documentation', permanent: true },
+ { source: '/quick-manual', destination: '/documentation', permanent: true },
{ source: '/support.html', destination: '/support', permanent: true },
- { source: '/license.html', destination: '/license', permanent: true },
+ { source: '/license.html', destination: '/support', permanent: true },
+ { source: '/license', destination: '/support', permanent: true },
];
diff --git a/src/test/setup.ts b/src/test/setup.ts
index bb02c60..a2585de 100644
--- a/src/test/setup.ts
+++ b/src/test/setup.ts
@@ -1 +1,15 @@
import '@testing-library/jest-dom/vitest';
+
+Object.defineProperty(window, 'matchMedia', {
+ writable: true,
+ value: (query: string) => ({
+ matches: false,
+ media: query,
+ onchange: null,
+ addListener: () => {},
+ removeListener: () => {},
+ addEventListener: () => {},
+ removeEventListener: () => {},
+ dispatchEvent: () => false,
+ }),
+});