Skip to content

Website changes as per audit doc. Release blog added#12

Open
reeshabh90 wants to merge 4 commits into
docwire:masterfrom
reeshabh90:reeshabh-web-changes
Open

Website changes as per audit doc. Release blog added#12
reeshabh90 wants to merge 4 commits into
docwire:masterfrom
reeshabh90:reeshabh-web-changes

Conversation

@reeshabh90
Copy link
Copy Markdown
Contributor

@reeshabh90 reeshabh90 commented Jun 1, 2026

  • New sections added
  • Intersection Observer effect in Website
  • Release blog updated

Summary by CodeRabbit

  • New Features

    • Redesigned home page with new marketing sections featuring scroll-reveal animations.
    • Latest release badge added to header.
    • Contact form now accepts pre-filled subject parameter via URL.
  • Documentation

    • Published DocWire SDK 2026.05.25 release notes documenting license migration to AGPLv3, improved content detection, and test infrastructure updates.
  • UI Updates

    • Footer redesigned with new branding, links, and copyright information.
    • Use Cases section refactored with enhanced layout.
    • Supported formats data expanded with new Medical category.
    • Enhanced animations and responsive design improvements.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR redesigns the DocWire marketing website's home page by replacing four outdated sections with six new marketing sections, each featuring scroll-reveal animations driven by IntersectionObserver. It updates the header with a GitHub release badge, redesigns the use-cases section into a client grid, and adds supporting configuration changes for forms, data, footer styling, and documentation.

Changes

Home Page Marketing Sections & Header Redesign

Layer / File(s) Summary
New Marketing Sections 2–4
src/containers/components/home/Section2.jsx, Section3.jsx, Section4.jsx, section2.css, section3.css, section4.css
Three new marketing sections with static data arrays and IntersectionObserver-driven scroll-reveal animations. Section2 renders scenario cards, Section3 renders capability cards with sticky intro, Section4 renders a 3-column format carousel with auto-advance and manual navigation.
Remaining Sections 5–6 & CTA
src/containers/components/home/Section5.jsx, Section6.jsx, SectionCTA.jsx, section5.css, section6.css, sectioncta.css
Three more new sections: Section5 renders a 2×2 grid of pillars, Section6 displays infrastructure content with code example and properties, SectionCTA renders a full-width call-to-action band. All use similar reveal-animation patterns with per-element staggered delays.
Header Release Badge & Animations
src/containers/header/home/HomeHeader.jsx, homeheader.css
Adds useLatestRelease hook to fetch GitHub release tag on mount and display a release badge with link. Updates header and slideshow-track animations with heroFadeUp keyframes and new release-button styling.
Module Exports & Page Wiring
src/containers/index.js, src/pages/index.js
Removes old section exports (SupportedFormats, HomeHaveYouEver, UnlockThePower, WingsSection) and adds new Section2–6 and SectionCTA exports. Updates Home page JSX to render the new sections.

Use Cases Section Redesign

Layer / File(s) Summary
Use Cases Refactor
src/containers/usecases/UseCases.jsx, usecases.css
Transforms use-cases from hero layout to client grid. Adds clientContext map for per-client text overrides, dynamic logo loading with try/catch fallback. Replaces entire CSS with new grid layout, header/divider/client cards, scroll-reveal animations, and responsive behavior.

Supporting Configuration & Data Updates

Layer / File(s) Summary
Contact Form Query Params
src/containers/components/contactUs/Form.jsx
Adds URL subject query parameter support via useLocation() and SUBJECT_MAP to pre-select the form reason dropdown.
Docusaurus Footer & Tagline
docusaurus.config.js, src/css/custom.css
Adds footer logo (dark/light variants) and updates footer links ("Use Cases", "Commercial Licence", "LTS Agreements"). Adds multi-organization copyright markup. Introduces .footer__tagline CSS styling.
Supported Formats Data
src/data/supportedFormatsData.js
Adds new "Medical" format group (DICOM, HL7) with BsHospital icon. Renames and expands existing format group descriptions. Moves DICOM from Structured Data to Medical group.
Release Documentation
blog/2026-06-01-docwire-release-2026.05.25.md
Adds release notes for SDK 2026.05.25 covering license change (GPLv2→AGPLv3), content-type detection heuristics, and test infrastructure refactoring.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • docwire/docwire.io#11: Modifies docusaurus.config.js footer configuration (logo, link sets, and copyright markup) in parallel with this PR's footer updates.
  • docwire/docwire.io#2: Both PRs change the home-page component wiring via src/containers/index.js and src/pages/index.js; the earlier PR introduced SupportedFormats while this PR removes it and replaces it with Section2–Section6.
  • docwire/docwire.io#3: The earlier PR introduced src/data/supportedFormatsData.js and the SupportedFormats component; this PR extends the data (adds Medical group) and removes the component.

Poem

🐰 Six new sections bloom in scroll-reveal grace,
Old layouts fade as animations take their place,
Release badges gleam with GitHub's gentle tap,
Client grids now showcase your trusted map,
From hero to heart, the journey's redesigned divine!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: website restructuring and a new release blog post, directly reflecting the audit-driven overhaul of home page sections and the DocWire SDK release documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request reorganizes and modernizes the DocWire SDK landing page by replacing legacy components with structured, animated sections (Sections 2–6 and SectionCTA), adding medical format support (DICOM/HL7), updating client use cases, and introducing a dynamic latest-release badge in the header. Feedback on these changes highlights several areas for improvement: fixing a broken markdown link in the release blog post, addressing a UX issue in the contact form that hides inputs before a successful submission, preventing a potential memory leak in the GitHub release fetch hook, and cleaning up several unused imports and dead code (such as the unused useScrollReveal hook).

Test Infrastructure
The monolithic api_tests.cpp has been split into focused files (core_tests.cpp, error_tests.cpp, log_tests.cpp, etc.), and all unit tests now run from a single docwire_tests binary. The practical effect is significantly reduced overhead during full test cycles under Valgrind.

[Full release notes](github.com/docwire/docwire/releases/tag/2026.05.25) No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The link is missing the https:// protocol. Without it, Docusaurus will resolve this as a relative path (e.g., /blog/github.com/...), resulting in a 404 error when clicked.

Suggested change
[Full release notes](github.com/docwire/docwire/releases/tag/2026.05.25)
[Full release notes](https://github.com/docwire/docwire/releases/tag/2026.05.25)

Comment on lines +27 to +53
function useScrollReveal(ref, options = {}) {
useEffect(() => {
const els = ref.current;
if (!els || els.length === 0) return;

const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("revealed");
// Don't unobserve — we want reverse animation on scroll up
} else {
entry.target.classList.remove("revealed");
}
});
},
{
threshold: 0.15,
rootMargin: "0px 0px -60px 0px",
...options,
}
);

els.forEach((el) => { if (el) observer.observe(el); });
return () => observer.disconnect();
}, []);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The custom hook useScrollReveal is defined but never used in this component. Instead, three separate useEffect hooks are defined to manually instantiate IntersectionObservers. To improve maintainability and reduce dead code, consider removing this unused hook or refactoring the component to utilize it.

Comment on lines 53 to 68
function handleOnSubmit(e) {
e.preventDefault()
setIsFormVisible(false)
emailjs.sendForm('service_vxi20hi',
e.preventDefault();
setIsFormVisible(false);
emailjs.sendForm(
'service_vxi20hi',
'template_m1jh747',
e.target, '-4RMv_gPIISLilkg8').then(res => {
console.log(res)
setState("success")
e.target,
'-4RMv_gPIISLilkg8'
).then(res => {
console.log(res);
setState("success");
}).catch(err => {
setState("fail")
console.log(err)
})
setState("fail");
console.log(err);
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting setIsFormVisible(false) immediately on submit hides the form before the email is actually sent. If the request fails, the user is shown an error message with no way to retrieve their input or retry the submission. Consider keeping the form visible during the loading state (disabling the submit button) and only hiding it upon a successful response. You can also render the error message inside the form when State === "fail".

Suggested change
function handleOnSubmit(e) {
e.preventDefault()
setIsFormVisible(false)
emailjs.sendForm('service_vxi20hi',
e.preventDefault();
setIsFormVisible(false);
emailjs.sendForm(
'service_vxi20hi',
'template_m1jh747',
e.target, '-4RMv_gPIISLilkg8').then(res => {
console.log(res)
setState("success")
e.target,
'-4RMv_gPIISLilkg8'
).then(res => {
console.log(res);
setState("success");
}).catch(err => {
setState("fail")
console.log(err)
})
setState("fail");
console.log(err);
});
}
function handleOnSubmit(e) {
e.preventDefault();
setState("loading");
emailjs.sendForm(
'service_vxi20hi',
'template_m1jh747',
e.target,
'-4RMv_gPIISLilkg8'
).then(res => {
console.log(res);
setState("success");
setIsFormVisible(false);
}).catch(err => {
setState("fail");
console.log(err);
});
}

Comment on lines +21 to +34
function useLatestRelease() {
const [version, setVersion] = useState(null);

useEffect(() => {
fetch("https://api.github.com/repos/docwire/docwire/releases/latest")
.then((r) => r.json())
.then((data) => {
if (data.tag_name) setVersion(data.tag_name);
})
.catch(() => { }); // fail silently — button still works without the badge
}, []);

return version;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the component unmounts while the fetch request is still in progress, calling setVersion when the promise resolves can cause a memory leak or state update warning on an unmounted component. Consider using a local isMounted flag to safely guard the state update.

function useLatestRelease() {
    const [version, setVersion] = useState(null);

    useEffect(() => {
        let isMounted = true;
        fetch("https://api.github.com/repos/docwire/docwire/releases/latest")
            .then((r) => r.json())
            .then((data) => {
                if (isMounted && data.tag_name) setVersion(data.tag_name);
            })
            .catch(() => { }); // fail silently — button still works without the badge

        return () => {
            isMounted = false;
        };
    }, []);

    return version;
}

@@ -0,0 +1,157 @@
import "./section3.css";
import React, { useEffect, useRef } from "react";
import Link from '@docusaurus/Link';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Link component is imported but never used in this file. It should be removed to keep the codebase clean and avoid potential build or linting warnings.

@@ -0,0 +1,113 @@
import "./section6.css";
import React, { useEffect, useRef } from "react";
import Link from '@docusaurus/Link';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Link component is imported but never used in this file. It should be removed to keep the codebase clean and avoid potential build or linting warnings.

Comment thread src/pages/index.js
Comment on lines 7 to 16
import {
WingsSection,
UnlockThePower,
HomeHaveYouEver,
Section6,
Section5,
Section2,
CTA,
HomeHeader,
SupportedFormats,
ClientsBanner
Section4,
ClientsBanner,
Section3, SectionCTA
} from "../containers";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CTA component is imported from ../containers but never used in the Home component. Removing it keeps the imports clean and avoids unused variable warnings.

import {
    Section6,
    Section5,
    Section2,
    HomeHeader,
    Section4,
    ClientsBanner,
    Section3, SectionCTA
} from "../containers";

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/css/custom.css (1)

424-436: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The tagline opacity is being compounded by the parent container.

Because .footer__copyright already sets opacity: 0.65, the new .footer__tagline opacity is multiplied on top of it instead of replacing it. If the tagline needs its own emphasis, move the opacity treatment off the parent or split the tagline into a separate container.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/css/custom.css` around lines 424 - 436, The issue is that
.footer__tagline's opacity is being multiplied by the parent .footer__copyright
opacity; remove opacity from the parent and instead express intended
transparency using color alpha values (e.g., use RGBA/HSLA) or place the tagline
outside .footer__copyright so it isn't a descendant; update .footer__copyright
to drop opacity and use color: rgba(...) for its text, and give .footer__tagline
its own color with the desired alpha (or keep it in a separate wrapper) so the
tagline's transparency is independent.
🧹 Nitpick comments (6)
src/containers/usecases/UseCases.jsx (1)

31-71: ⚡ Quick win

Wire this section into the reveal system or drop the unused animation CSS.

Nothing rendered here gets scroll-reveal / reveal-up, and this component never registers an IntersectionObserver, so the new reveal rules in usecases.css never run. If this section is supposed to match the Section2–Section6 behavior, add the same class/ref wiring to the header and client cards.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/usecases/UseCases.jsx` around lines 31 - 71, The header and
client cards in UseCases.jsx aren't hooked into the reveal system—add the same
reveal wiring used by Section2–Section6: give the header element
(docwire__usecases__header) and each client block (docwire__usecases__client
and/or client-top) the reveal classes (e.g., "scroll-reveal" and "reveal-up")
and create refs for the header and the client card elements inside the data.map;
in a useEffect register those refs with the existing IntersectionObserver/reveal
registration used elsewhere (mirror the observer setup and cleanup logic from
Section2–Section6) so the CSS rules in usecases.css actually run when these
elements scroll into view.
src/containers/components/home/Section6.jsx (1)

39-48: 💤 Low value

ctaRef is unused. No element binds ctaRef, so it is always null and filtered out of targets. Safe to remove to avoid confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/Section6.jsx` around lines 39 - 48, Remove the
unused ctaRef: delete the const ctaRef = useRef(null) declaration and remove
ctaRef.current from the targets array inside the useEffect (where
headerRef.current, bodyRef.current, codeRef.current, propsRef.current are
collected), or alternatively bind ctaRef to the CTA element if it was intended
to be used; update only the ctaRef occurrences (declaration and .current
reference) so headerRef/bodyRef/codeRef/propsRef logic remains unchanged.
src/containers/header/home/HomeHeader.jsx (1)

24-31: ⚡ Quick win

Add cleanup to the fetch effect. The effect has no abort/cancellation, so a fetch resolving after unmount calls setVersion on an unmounted component (and StrictMode double-invokes the effect in dev). Use AbortController to cancel in-flight requests.

♻️ Proposed fix
     useEffect(() => {
-        fetch("https://api.github.com/repos/docwire/docwire/releases/latest")
+        const controller = new AbortController();
+        fetch("https://api.github.com/repos/docwire/docwire/releases/latest", { signal: controller.signal })
             .then((r) => r.json())
             .then((data) => {
                 if (data.tag_name) setVersion(data.tag_name);
             })
             .catch(() => { }); // fail silently — button still works without the badge
-    }, []);
+        return () => controller.abort();
+    }, []);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/header/home/HomeHeader.jsx` around lines 24 - 31, The effect
using fetch in useEffect should create an AbortController and pass its signal to
fetch (the request to
"https://api.github.com/repos/docwire/docwire/releases/latest") so it can be
cancelled; update the .catch to ignore AbortError (or check error.name ===
'AbortError') and avoid calling setVersion when the request was aborted, and
return a cleanup function that calls controller.abort() to cancel in-flight
requests on unmount (affecting the useEffect, fetch call, and setVersion usage).
src/containers/components/home/section6.css (1)

81-86: 💤 Low value

Remove the empty duplicate selector. This .s6__code-block code block contains only a comment and no declarations, duplicating the rule above it.

♻️ Proposed cleanup
-/* Colour the pipe operators */
-.s6__code-block code {
-    /* We inject a CSS trick: wrap pipe chars visually via a ::before overlay isn't
-       possible in plain text, so we colour the whole block and rely on the
-       violet border to carry the accent. The brand palette reads cleanly here. */
-}
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/section6.css` around lines 81 - 86, The
.s6__code-block code selector is an empty duplicate containing only a comment;
remove this redundant rule to avoid duplication and keep stylesheet clean by
deleting the empty block (the selector ".s6__code-block code") so the remaining
declarations for that element are only defined once.
src/containers/header/home/homeheader.css (1)

14-22: 💤 Low value

Lint: keyframe name not kebab-case. Stylelint flags heroFadeUp; rename to hero-fade-up (and update the three animation: references in this file) to satisfy keyframes-name-pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/header/home/homeheader.css` around lines 14 - 22, Rename the
keyframes identifier heroFadeUp to kebab-case hero-fade-up in the `@keyframes`
declaration and update all animation usages that reference heroFadeUp (there are
three animation: occurrences in this file) to use hero-fade-up so the
keyframes-name-pattern lint rule passes; ensure both the `@keyframes` block and
every animation/animation-name reference are changed consistently.
src/containers/components/home/section4.css (1)

157-157: ⚡ Quick win

Replace deprecated word-break: break-word.

word-break: break-word is deprecated. Use overflow-wrap: break-word for the same wrapping behavior on long format strings.

♻️ Proposed fix
-    word-break: break-word;
+    overflow-wrap: break-word;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/section4.css` at line 157, Replace the
deprecated CSS declaration "word-break: break-word" with the modern equivalent
by removing that property and adding "overflow-wrap: break-word" (and optionally
keep "word-break: normal" if explicit word-break behavior is needed); update the
rule containing "word-break: break-word" in section4.css so long strings wrap
correctly using overflow-wrap.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@blog/2026-06-01-docwire-release-2026.05.25.md`:
- Around line 8-16: Update the Markdown heading hierarchy so top-level sections
use consistent h2 headings instead of h3: change "### License: GPLv2 → AGPLv3"
and "### Content Type Detection: Heuristic Pipeline" to "##" and convert the
plain "Test Infrastructure" line into a matching heading (e.g., "## Test
Infrastructure"); ensure appropriate blank lines around these headings for
proper rendering and accessibility.

In `@docusaurus.config.js`:
- Around line 124-130: The footer logo currently hardcodes
themeConfig.footer.logo.href to "/" which breaks navigation when the site runs
under a non-root baseUrl; update the docusaurus.config.js configuration so
themeConfig.footer.logo.href uses the computed baseUrl (siteConfig.baseUrl or
the exported baseUrl constant) or remove the href property to fall back to
Docusaurus defaults; locate themeConfig.footer.logo in docusaurus.config.js and
replace the literal "/" with the baseUrl variable/reference used elsewhere in
this file (or simply omit href) so the link respects the configured baseUrl.

In `@src/containers/components/contactUs/Form.jsx`:
- Around line 53-67: In handleOnSubmit, set the form state to "loading" before
calling emailjs.sendForm, do not call setIsFormVisible(false) until the sendForm
promise resolves successfully (call setIsFormVisible(false) and
setState("success") inside the .then), and on .catch restore visibility
(setIsFormVisible(true)) and setState("fail") so the form remains interactive
for retries; ensure the button uses disabled={State === "loading"} so the
loading guard works. Apply the same changes to the other submit handler
duplicate in this file.

In `@src/containers/components/home/section2.css`:
- Around line 74-91: Currently .reveal-up sets opacity:0 and translateY by
default causing content to be invisible until JS runs; change the CSS so content
is visible by default and the "hidden" state is only applied via a class added
by client-side code. Concretely, remove the default opacity:0 and transform from
.reveal-up and instead create a host-only hidden class (e.g.
.reveal-up.js-hidden or .scroll-reveal--hidden) that contains opacity:0 and
transform: translateY(28px); keep .reveal-up.revealed (or the existing .revealed
toggle) to restore visibility; also update the IntersectionObserver code to
add/remove that js-hidden class rather than relying on the element being hidden
by default. This ensures .scroll-reveal/.reveal-up are visible without JS and
still animate when the observer toggles the hidden/revealed classes.

In `@src/containers/components/home/section3.css`:
- Around line 119-135: The current CSS makes .reveal-up start hidden
(opacity:0), which hides content when JS doesn’t run; instead make the default
visible and apply the hidden starting state only after the app mounts by moving
the hidden rules behind a JS-mounted selector: remove opacity:0/translateY from
.reveal-up so it defaults visible, then add a selector such as .js-mounted
.reveal-up { opacity: 0; transform: translateY(28px); transition-delay:
var(--delay, 0ms); } while keeping .reveal-up.revealed (or .js-mounted
.reveal-up.revealed) to animate to opacity:1/translateY(0); ensure your mount
script adds the .js-mounted class to the root element so the reveal observer
still works without breaking no-JS fallbacks.

In `@src/containers/components/home/Section4.jsx`:
- Around line 121-122: The visible-range counter using startIndex, VISIBLE and
total produces misleading wrapped intervals (e.g., "7 – 1 of 8"); change the
rendering logic in Section4.jsx/inside the element with className "s4__counter"
to detect wrapping and instead compute the visible positions array (for i in
0..VISIBLE-1 use (startIndex + i) % total + 1), join them with commas into a
string like "7, 8, 1 of 8" or render a non-range phrase "Showing X of Y format
groups" (choose one consistent UI style), and replace the current range
expression {startIndex + 1} – {((startIndex + VISIBLE - 1) % total) + 1} of
{total} with the new computed string.
- Around line 109-118: The dot buttons currently use a tabs pattern without
panels and must either be converted to a non-tab ARIA pattern or fully implement
tabs semantics: change the container role from role="tablist" and each button
role="tab" to an appropriate non-tabs role (e.g., role="list" / <no role> or
role="radiogroup" + role="radio") or, if you want tabs, add matching tabpanel
elements and wiring (add aria-controls on each button pointing to a panel id,
ensure panels have role="tabpanel" and aria-labelledby) and implement required
keyboard/focus behavior in goTo to satisfy the tabs contract; also fix the
visible-counter display logic that uses startIndex, VISIBLE and total so wrapped
ranges aren’t shown backwards—compute endIndex = (startIndex + VISIBLE - 1) %
total and render "start–end" when endIndex >= startIndex, otherwise render
"start–total, 1–end" (use the same startIndex, VISIBLE, total, formatGroups and
goTo references).

In `@src/containers/components/home/SectionCTA.jsx`:
- Around line 38-42: The paragraph in the SectionCTA component references the
wrong license; update the copy in SectionCTA.jsx (the paragraph inside the
SectionCTA component) to replace "GPLv2" with "AGPLv3" so it matches the rest of
the site (and Section6.jsx's "AGPLv3 licensed core"); ensure the wording remains
grammatically identical aside from the license token.

In `@src/containers/usecases/UseCases.jsx`:
- Around line 16-19: The PwC override object key is incorrect: change the 'pwc'
key in the overrides map to the actual linkName 'pwc-singapore' so clientContext
lookup (which uses item.linkName) will match and not fall back to
showcasesShortInfo; update the object key where the PwC override is defined in
UseCases.jsx (the entry currently labeled "pwc") to "pwc-singapore" and keep the
existing sector/outcome values intact.

In `@src/data/supportedFormatsData.js`:
- Around line 17-22: Update the description for the Medical entry in
supportedFormatsData (the object with groupName "Medical", icon BsHospital,
formats ["DICOM (DCM)", "HL7"]) to remove the compliance attestation "validated
for HIPAA-regulated environments" and replace it with a factual capability
statement (e.g., describe supported parsing features like "parsing and metadata
extraction for DICOM and HL7 formats" or "production-tested parsing for DICOM
metadata extraction and HL7 message traversal") so it conveys functionality
without claiming formal regulatory validation.

---

Outside diff comments:
In `@src/css/custom.css`:
- Around line 424-436: The issue is that .footer__tagline's opacity is being
multiplied by the parent .footer__copyright opacity; remove opacity from the
parent and instead express intended transparency using color alpha values (e.g.,
use RGBA/HSLA) or place the tagline outside .footer__copyright so it isn't a
descendant; update .footer__copyright to drop opacity and use color: rgba(...)
for its text, and give .footer__tagline its own color with the desired alpha (or
keep it in a separate wrapper) so the tagline's transparency is independent.

---

Nitpick comments:
In `@src/containers/components/home/section4.css`:
- Line 157: Replace the deprecated CSS declaration "word-break: break-word" with
the modern equivalent by removing that property and adding "overflow-wrap:
break-word" (and optionally keep "word-break: normal" if explicit word-break
behavior is needed); update the rule containing "word-break: break-word" in
section4.css so long strings wrap correctly using overflow-wrap.

In `@src/containers/components/home/section6.css`:
- Around line 81-86: The .s6__code-block code selector is an empty duplicate
containing only a comment; remove this redundant rule to avoid duplication and
keep stylesheet clean by deleting the empty block (the selector ".s6__code-block
code") so the remaining declarations for that element are only defined once.

In `@src/containers/components/home/Section6.jsx`:
- Around line 39-48: Remove the unused ctaRef: delete the const ctaRef =
useRef(null) declaration and remove ctaRef.current from the targets array inside
the useEffect (where headerRef.current, bodyRef.current, codeRef.current,
propsRef.current are collected), or alternatively bind ctaRef to the CTA element
if it was intended to be used; update only the ctaRef occurrences (declaration
and .current reference) so headerRef/bodyRef/codeRef/propsRef logic remains
unchanged.

In `@src/containers/header/home/homeheader.css`:
- Around line 14-22: Rename the keyframes identifier heroFadeUp to kebab-case
hero-fade-up in the `@keyframes` declaration and update all animation usages that
reference heroFadeUp (there are three animation: occurrences in this file) to
use hero-fade-up so the keyframes-name-pattern lint rule passes; ensure both the
`@keyframes` block and every animation/animation-name reference are changed
consistently.

In `@src/containers/header/home/HomeHeader.jsx`:
- Around line 24-31: The effect using fetch in useEffect should create an
AbortController and pass its signal to fetch (the request to
"https://api.github.com/repos/docwire/docwire/releases/latest") so it can be
cancelled; update the .catch to ignore AbortError (or check error.name ===
'AbortError') and avoid calling setVersion when the request was aborted, and
return a cleanup function that calls controller.abort() to cancel in-flight
requests on unmount (affecting the useEffect, fetch call, and setVersion usage).

In `@src/containers/usecases/UseCases.jsx`:
- Around line 31-71: The header and client cards in UseCases.jsx aren't hooked
into the reveal system—add the same reveal wiring used by Section2–Section6:
give the header element (docwire__usecases__header) and each client block
(docwire__usecases__client and/or client-top) the reveal classes (e.g.,
"scroll-reveal" and "reveal-up") and create refs for the header and the client
card elements inside the data.map; in a useEffect register those refs with the
existing IntersectionObserver/reveal registration used elsewhere (mirror the
observer setup and cleanup logic from Section2–Section6) so the CSS rules in
usecases.css actually run when these elements scroll into view.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7b0f2394-aba6-4700-a63b-046a93294d4c

📥 Commits

Reviewing files that changed from the base of the PR and between af5aba7 and fcf7cd8.

⛔ Files ignored due to path filters (2)
  • static/img/LogoFrame_Black.png is excluded by !**/*.png
  • static/img/LogoFrame_White.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • blog/2026-06-01-docwire-release-2026.05.25.md
  • docusaurus.config.js
  • src/containers/components/contactUs/Form.jsx
  • src/containers/components/home/HomeHaveYouEver.jsx
  • src/containers/components/home/Section2.jsx
  • src/containers/components/home/Section3.jsx
  • src/containers/components/home/Section4.jsx
  • src/containers/components/home/Section5.jsx
  • src/containers/components/home/Section6.jsx
  • src/containers/components/home/SectionCTA.jsx
  • src/containers/components/home/SupportedFormats.jsx
  • src/containers/components/home/UnlockThePower.jsx
  • src/containers/components/home/WingsSection.jsx
  • src/containers/components/home/homehaveyouever.css
  • src/containers/components/home/section2.css
  • src/containers/components/home/section3.css
  • src/containers/components/home/section4.css
  • src/containers/components/home/section5.css
  • src/containers/components/home/section6.css
  • src/containers/components/home/sectioncta.css
  • src/containers/components/home/supportedFormats.css
  • src/containers/components/home/unlockthepower.css
  • src/containers/components/home/wingssection.css
  • src/containers/header/home/HomeHeader.jsx
  • src/containers/header/home/homeheader.css
  • src/containers/index.js
  • src/containers/usecases/UseCases.jsx
  • src/containers/usecases/usecases.css
  • src/css/custom.css
  • src/data/supportedFormatsData.js
  • src/pages/index.js
💤 Files with no reviewable changes (8)
  • src/containers/components/home/supportedFormats.css
  • src/containers/components/home/homehaveyouever.css
  • src/containers/components/home/SupportedFormats.jsx
  • src/containers/components/home/WingsSection.jsx
  • src/containers/components/home/HomeHaveYouEver.jsx
  • src/containers/components/home/unlockthepower.css
  • src/containers/components/home/UnlockThePower.jsx
  • src/containers/components/home/wingssection.css

Comment on lines +8 to +16
### License: GPLv2 → AGPLv3
DocWire SDK moves from GPLv2 to the GNU Affero General Public License v3.0.
The practical differences matter. AGPLv3 closes the "SaaS loophole" — under GPLv2, a company could run DocWire as a networked service without releasing their source code. AGPLv3 requires that network users also receive source. Beyond that, AGPLv3 includes explicit patent grants protecting users from litigation by contributors, is compatible with Apache License 2.0 which broadens ecosystem integration, and uses more internationally enforceable legal language.
For internal tooling, research, and open-source projects: nothing changes. For proprietary networked services, AGPLv3 is not compatible with closed-source deployment under its open-source terms. DocWire is dual-licensed — a commercial license is available for organizations that need to deploy without AGPLv3 obligations
### Content Type Detection: Heuristic Pipeline
Content type detection is where document processing pipelines fail quietly. The symptom is wrong output or silent failures; the cause is usually a file that doesn't match what libmagic expects — wrong extension, missing metadata, or a non-seekable network stream.
This release introduces specialized heuristic detectors for images (BMP, WEBP) and ZIP-based containers (OOXML, ODF formats — DOCX, XLSX, PPTX). The approach: check local file headers in the first 4KB before falling back to deep inspection. This specifically addresses detection failures on non-seekable streams with libmagic 5.47+, where the previous approach regressed.
Two additional fixes come with this: MIME type normalization now standardizes legacy types returned by libmagic to modern IANA standards (e.g. text/xml → application/xml), and when multiple MIME types have identical confidence scores, the result is now alphabetically deterministic rather than platform-dependent.
Test Infrastructure
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the section heading hierarchy in the release post.

The post jumps straight to ### headings, and Test Infrastructure is left as body text. That breaks markdown heading structure (MD001) and makes the post harder to scan.

Proposed fix
-### License: GPLv2 → AGPLv3
+## License: GPLv2 → AGPLv3
 ...
-### Content Type Detection: Heuristic Pipeline
+## Content Type Detection: Heuristic Pipeline
 ...
-Test Infrastructure
+## Test Infrastructure
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### License: GPLv2 → AGPLv3
DocWire SDK moves from GPLv2 to the GNU Affero General Public License v3.0.
The practical differences matter. AGPLv3 closes the "SaaS loophole" — under GPLv2, a company could run DocWire as a networked service without releasing their source code. AGPLv3 requires that network users also receive source. Beyond that, AGPLv3 includes explicit patent grants protecting users from litigation by contributors, is compatible with Apache License 2.0 which broadens ecosystem integration, and uses more internationally enforceable legal language.
For internal tooling, research, and open-source projects: nothing changes. For proprietary networked services, AGPLv3 is not compatible with closed-source deployment under its open-source terms. DocWire is dual-licensed — a commercial license is available for organizations that need to deploy without AGPLv3 obligations
### Content Type Detection: Heuristic Pipeline
Content type detection is where document processing pipelines fail quietly. The symptom is wrong output or silent failures; the cause is usually a file that doesn't match what libmagic expects — wrong extension, missing metadata, or a non-seekable network stream.
This release introduces specialized heuristic detectors for images (BMP, WEBP) and ZIP-based containers (OOXML, ODF formats — DOCX, XLSX, PPTX). The approach: check local file headers in the first 4KB before falling back to deep inspection. This specifically addresses detection failures on non-seekable streams with libmagic 5.47+, where the previous approach regressed.
Two additional fixes come with this: MIME type normalization now standardizes legacy types returned by libmagic to modern IANA standards (e.g. text/xml → application/xml), and when multiple MIME types have identical confidence scores, the result is now alphabetically deterministic rather than platform-dependent.
Test Infrastructure
## License: GPLv2 → AGPLv3
DocWire SDK moves from GPLv2 to the GNU Affero General Public License v3.0.
The practical differences matter. AGPLv3 closes the "SaaS loophole" — under GPLv2, a company could run DocWire as a networked service without releasing their source code. AGPLv3 requires that network users also receive source. Beyond that, AGPLv3 includes explicit patent grants protecting users from litigation by contributors, is compatible with Apache License 2.0 which broadens ecosystem integration, and uses more internationally enforceable legal language.
For internal tooling, research, and open-source projects: nothing changes. For proprietary networked services, AGPLv3 is not compatible with closed-source deployment under its open-source terms. DocWire is dual-licensed — a commercial license is available for organizations that need to deploy without AGPLv3 obligations
## Content Type Detection: Heuristic Pipeline
Content type detection is where document processing pipelines fail quietly. The symptom is wrong output or silent failures; the cause is usually a file that doesn't match what libmagic expects — wrong extension, missing metadata, or a non-seekable network stream.
This release introduces specialized heuristic detectors for images (BMP, WEBP) and ZIP-based containers (OOXML, ODF formats — DOCX, XLSX, PPTX). The approach: check local file headers in the first 4KB before falling back to deep inspection. This specifically addresses detection failures on non-seekable streams with libmagic 5.47+, where the previous approach regressed.
Two additional fixes come with this: MIME type normalization now standardizes legacy types returned by libmagic to modern IANA standards (e.g. text/xml → application/xml), and when multiple MIME types have identical confidence scores, the result is now alphabetically deterministic rather than platform-dependent.
## Test Infrastructure
🧰 Tools
🪛 LanguageTool

[style] ~11-~11: Consider using “incompatible” to avoid wordiness.
Context: ...oprietary networked services, AGPLv3 is not compatible with closed-source deployment under its...

(NOT_ABLE_PREMIUM)

🪛 markdownlint-cli2 (0.22.1)

[warning] 8-8: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@blog/2026-06-01-docwire-release-2026.05.25.md` around lines 8 - 16, Update
the Markdown heading hierarchy so top-level sections use consistent h2 headings
instead of h3: change "### License: GPLv2 → AGPLv3" and "### Content Type
Detection: Heuristic Pipeline" to "##" and convert the plain "Test
Infrastructure" line into a matching heading (e.g., "## Test Infrastructure");
ensure appropriate blank lines around these headings for proper rendering and
accessibility.

Comment thread docusaurus.config.js
Comment on lines +124 to +130
logo: {
alt: 'DocWire SDK',
src: 'img/LogoFrame_Black.png',
srcDark: 'img/LogoFrame_White.png',
href: '/',
width: 120,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Docusaurus 3.9.2, does themeConfig.footer.logo.href="/" navigate to the domain root instead of honoring baseUrl on GitHub Pages deployments, and is using the computed baseUrl the recommended fix?

💡 Result:

Yes and no: 1) Does themeConfig.footer.logo.href="/" navigate to the domain root instead of honoring baseUrl? - In Docusaurus 3.9.2, the footer logo’s href option is documented as a full-page navigation (separate from client-side routing). The default value for footer logo href is siteConfig.baseUrl [1]. Therefore, if you explicitly set footer.logo.href to the literal string "/", the browser will navigate to the domain root (that string is not “computed” from baseUrl). - Docusaurus’ automatic baseUrl prepending applies to themeConfig.footer.links entries using the "to" field (“baseUrl will be automatically prepended”) but it does not say the same for a literal "href" override [1]. So the most direct reading of the API contract is: hard-coding href="/" overrides baseUrl-based behavior. 2) Is using the computed baseUrl the recommended fix? - Yes. The docs explicitly define baseUrl as the path segment under which the site is served [2][3], and they state that logo.href defaults to siteConfig.baseUrl [1]. So the recommended fix is to not hard-code "/"; instead rely on the computed baseUrl (i.e., use the default behavior or set href to your computed baseUrl value, such as siteConfig.baseUrl). Practical recommendation for GitHub Pages: - Set the correct docusaurus.config baseUrl for the GitHub Pages project subpath (for example, "//"), and ensure trailingSlash is set intentionally for GitHub Pages routing [4]. Then leave themeConfig.footer.logo.href unset (or set it to siteConfig.baseUrl) rather than forcing "/" [1]. Notes: - I did not find a Docusaurus 3.9.2-specific changelog entry or issue explicitly describing this exact "footer.logo.href" + "baseUrl" interaction on GitHub Pages; the answer above is based on the documented API defaults/semantics for footer logo href and baseUrl usage [1].

Citations:


Fix footer logo navigation to respect Docusaurus baseUrl

Hard-coding docusaurus.config.js themeConfig.footer.logo.href to the literal "/" will navigate to the domain root instead of the site’s configured baseUrl path (Docusaurus default logo.href is siteConfig.baseUrl; baseUrl prepending is documented for footer.links via to, not a literal href). On GitHub Pages served from a subpath, clicking the logo will go to the wrong location.
Set logo.href to the computed baseUrl for the current build (or omit href to use the default).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docusaurus.config.js` around lines 124 - 130, The footer logo currently
hardcodes themeConfig.footer.logo.href to "/" which breaks navigation when the
site runs under a non-root baseUrl; update the docusaurus.config.js
configuration so themeConfig.footer.logo.href uses the computed baseUrl
(siteConfig.baseUrl or the exported baseUrl constant) or remove the href
property to fall back to Docusaurus defaults; locate themeConfig.footer.logo in
docusaurus.config.js and replace the literal "/" with the baseUrl
variable/reference used elsewhere in this file (or simply omit href) so the link
respects the configured baseUrl.

Comment on lines 53 to +67
function handleOnSubmit(e) {
e.preventDefault()
setIsFormVisible(false)
emailjs.sendForm('service_vxi20hi',
e.preventDefault();
setIsFormVisible(false);
emailjs.sendForm(
'service_vxi20hi',
'template_m1jh747',
e.target, '-4RMv_gPIISLilkg8').then(res => {
console.log(res)
setState("success")
e.target,
'-4RMv_gPIISLilkg8'
).then(res => {
console.log(res);
setState("success");
}).catch(err => {
setState("fail")
console.log(err)
})
setState("fail");
console.log(err);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the form visible until the send succeeds.

The form is hidden before emailjs.sendForm(...) resolves, so any transient failure leaves the user on a non-interactive error state with no retry path. The disabled={State === "loading"} guard also never activates because "loading" is never set.

Proposed fix
 function handleOnSubmit(e) {
     e.preventDefault();
-    setIsFormVisible(false);
+    setState("loading");
     emailjs.sendForm(
         'service_vxi20hi',
         'template_m1jh747',
         e.target,
         '-4RMv_gPIISLilkg8'
     ).then(res => {
         console.log(res);
+        setIsFormVisible(false);
         setState("success");
     }).catch(err => {
         setState("fail");
         console.log(err);
     });
 }

Also applies to: 105-118

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/contactUs/Form.jsx` around lines 53 - 67, In
handleOnSubmit, set the form state to "loading" before calling emailjs.sendForm,
do not call setIsFormVisible(false) until the sendForm promise resolves
successfully (call setIsFormVisible(false) and setState("success") inside the
.then), and on .catch restore visibility (setIsFormVisible(true)) and
setState("fail") so the form remains interactive for retries; ensure the button
uses disabled={State === "loading"} so the loading guard works. Apply the same
changes to the other submit handler duplicate in this file.

Comment on lines +74 to +91
.scroll-reveal {
will-change: opacity, transform;
transition:
opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
/* Use delay via CSS custom property set inline */
transition-delay: var(--delay, 0ms);
}

.reveal-up {
opacity: 0;
transform: translateY(28px);
}

.reveal-up.revealed {
opacity: 1;
transform: translateY(0);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t make the section content depend on JavaScript to become visible.

These rules hide the copy by default and only reveal it after IntersectionObserver runs. If JS fails, hydration breaks, or the API is unavailable, this entire section stays invisible. Default to visible content and only opt into the hidden state after client-side initialization.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/section2.css` around lines 74 - 91, Currently
.reveal-up sets opacity:0 and translateY by default causing content to be
invisible until JS runs; change the CSS so content is visible by default and the
"hidden" state is only applied via a class added by client-side code.
Concretely, remove the default opacity:0 and transform from .reveal-up and
instead create a host-only hidden class (e.g. .reveal-up.js-hidden or
.scroll-reveal--hidden) that contains opacity:0 and transform: translateY(28px);
keep .reveal-up.revealed (or the existing .revealed toggle) to restore
visibility; also update the IntersectionObserver code to add/remove that
js-hidden class rather than relying on the element being hidden by default. This
ensures .scroll-reveal/.reveal-up are visible without JS and still animate when
the observer toggles the hidden/revealed classes.

Comment on lines +119 to +135
.scroll-reveal {
will-change: opacity, transform;
transition:
opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
transition-delay: var(--delay, 0ms);
}

.reveal-up {
opacity: 0;
transform: translateY(28px);
}

.reveal-up.revealed {
opacity: 1;
transform: translateY(0);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

This reveal pattern still hides content permanently when client-side JS doesn’t run.

The intro copy, cards, and CTA all start at opacity: 0 and only appear after the observer fires. That makes this section fail closed for no-JS and client-error cases. Keep the default state visible, then add the animated hidden state only after mount.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/section3.css` around lines 119 - 135, The
current CSS makes .reveal-up start hidden (opacity:0), which hides content when
JS doesn’t run; instead make the default visible and apply the hidden starting
state only after the app mounts by moving the hidden rules behind a JS-mounted
selector: remove opacity:0/translateY from .reveal-up so it defaults visible,
then add a selector such as .js-mounted .reveal-up { opacity: 0; transform:
translateY(28px); transition-delay: var(--delay, 0ms); } while keeping
.reveal-up.revealed (or .js-mounted .reveal-up.revealed) to animate to
opacity:1/translateY(0); ensure your mount script adds the .js-mounted class to
the root element so the reveal observer still works without breaking no-JS
fallbacks.

Comment on lines +109 to +118
<div className="s4__dots" role="tablist" aria-label="Format group navigation">
{formatGroups.map((_, i) => (
<button
key={i}
role="tab"
aria-selected={i === startIndex}
aria-label={`Format group ${i + 1}`}
className={`s4__dot${i === startIndex ? " active" : ""}`}
onClick={() => goTo(i)}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

WAI-ARIA tabs pattern requirements for elements using role="tablist" and role="tab", including keyboard behavior and required relationships

💡 Result:

The WAI-ARIA tabs pattern is a composite UI component consisting of a tab list (role="tablist") and its associated tab elements (role="tab"), which control content panels (role="tabpanel") [1][2]. Required Elements and Relationships: - tablist: The container for the set of tabs [1][2]. It must contain at least one tab [2]. If the list is vertically oriented, set aria-orientation="vertical" (the default is "horizontal") [1][2]. It should be labeled via aria-label or aria-labelledby [1]. - tab: Each tab element must have the role="tab" and be a direct child of the tablist [1][3]. It must have aria-controls set to the ID of its corresponding tabpanel [1][4]. The active tab must have aria-selected="true", while inactive tabs have aria-selected="false" [1][4]. - tabpanel: Each panel has role="tabpanel" and should be labeled by its corresponding tab using aria-labelledby [1][4]. Keyboard Behavior: The tabs pattern uses a roving tabindex to manage focus within the tablist [4][5]. Only the active tab (or the first tab, if none are active) should be in the page's tab sequence (tabindex="0"); all other tabs should have tabindex="-1" [1][4][5]. Key bindings for the active tab when focused include [5]: - Left/Right Arrow (or Up/Down for vertical): Moves focus to the previous or next tab, respectively, wrapping around at the ends [5]. - Home: Moves focus to the first tab [5]. - End: Moves focus to the last tab [5]. - Enter or Space: Activates the tab (if using manual activation) [5]. For navigation out of the component, pressing Tab moves focus from the tablist to the associated tabpanel (if the panel contains focusable elements) or the next focusable element on the page [4][5][6]. If focus is inside a panel, Shift + Tab can be used to return to the active tab [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="src/containers/components/home/Section4.jsx"
# show around lines 80-170 with line numbers
nl -ba "$FILE" | sed -n '70,190p'

Repository: docwire/docwire.io

Length of output: 105


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="src/containers/components/home/Section4.jsx"
# show around lines 80-170 with line numbers
nl -ba "$FILE" | sed -n '70,190p'

Repository: docwire/docwire.io

Length of output: 105


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="src/containers/components/home/Section4.jsx"
# show around lines 70-190 with line numbers
cat -n "$FILE" | sed -n '70,190p'

Repository: docwire/docwire.io

Length of output: 3375


Fix ARIA tab semantics and make the wrapped counter range unambiguous

  • src/containers/components/home/Section4.jsx:109-120: the dot buttons use role="tablist"/role="tab" but there’s no corresponding role="tabpanel" content and no required tab-to-panel wiring (e.g., aria-controls / aria-labelledby), so they currently describe a “tabs” pattern without fulfilling the tabs contract (including expected keyboard/focus semantics).
  • src/containers/components/home/Section4.jsx:121-123: the counter uses modulo wrapping ({startIndex + 1} – {((startIndex + VISIBLE - 1) % total) + 1}), so when it wraps the end index can become smaller than the start index (e.g., “7–2”), which is confusing—format it as a wrapped range (e.g., “7–10, 1–2”) or change the display to avoid backwards ranges.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/Section4.jsx` around lines 109 - 118, The dot
buttons currently use a tabs pattern without panels and must either be converted
to a non-tab ARIA pattern or fully implement tabs semantics: change the
container role from role="tablist" and each button role="tab" to an appropriate
non-tabs role (e.g., role="list" / <no role> or role="radiogroup" +
role="radio") or, if you want tabs, add matching tabpanel elements and wiring
(add aria-controls on each button pointing to a panel id, ensure panels have
role="tabpanel" and aria-labelledby) and implement required keyboard/focus
behavior in goTo to satisfy the tabs contract; also fix the visible-counter
display logic that uses startIndex, VISIBLE and total so wrapped ranges aren’t
shown backwards—compute endIndex = (startIndex + VISIBLE - 1) % total and render
"start–end" when endIndex >= startIndex, otherwise render "start–total, 1–end"
(use the same startIndex, VISIBLE, total, formatGroups and goTo references).

Comment on lines +121 to +122
<p className="s4__counter" aria-live="polite">
{startIndex + 1} – {((startIndex + VISIBLE - 1) % total) + 1} of {total} format groups
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The visible-range counter becomes misleading at the wrap boundary.

When startIndex is near the end, this can render ranges like 7 – 1 of 8 format groups, which reads like a broken interval. Render a wrapped list of visible positions or switch the message to something non-range-based.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/Section4.jsx` around lines 121 - 122, The
visible-range counter using startIndex, VISIBLE and total produces misleading
wrapped intervals (e.g., "7 – 1 of 8"); change the rendering logic in
Section4.jsx/inside the element with className "s4__counter" to detect wrapping
and instead compute the visible positions array (for i in 0..VISIBLE-1 use
(startIndex + i) % total + 1), join them with commas into a string like "7, 8, 1
of 8" or render a non-range phrase "Showing X of Y format groups" (choose one
consistent UI style), and replace the current range expression {startIndex + 1}
– {((startIndex + VISIBLE - 1) % total) + 1} of {total} with the new computed
string.

Comment on lines +38 to +42
<p>
DocWire SDK is available as open-source under GPLv2, or under a commercial
licence for proprietary deployments. Long-Term Support agreements are available
for teams that need API stability across multi-year programmes.
</p>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stale license reference: should be AGPLv3, not GPLv2. This same PR's release blog documents the license change from GPLv2 to AGPLv3, and Section6.jsx (Line 20) already advertises an "AGPLv3 licensed core." This public-facing CTA still states GPLv2, which is now incorrect and contradicts the rest of the page.

🐛 Proposed fix
-                        DocWire SDK is available as open-source under GPLv2, or under a commercial
+                        DocWire SDK is available as open-source under AGPLv3, or under a commercial
                         licence for proprietary deployments. Long-Term Support agreements are available
                         for teams that need API stability across multi-year programmes.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<p>
DocWire SDK is available as open-source under GPLv2, or under a commercial
licence for proprietary deployments. Long-Term Support agreements are available
for teams that need API stability across multi-year programmes.
</p>
<p>
DocWire SDK is available as open-source under AGPLv3, or under a commercial
licence for proprietary deployments. Long-Term Support agreements are available
for teams that need API stability across multi-year programmes.
</p>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/components/home/SectionCTA.jsx` around lines 38 - 42, The
paragraph in the SectionCTA component references the wrong license; update the
copy in SectionCTA.jsx (the paragraph inside the SectionCTA component) to
replace "GPLv2" with "AGPLv3" so it matches the rest of the site (and
Section6.jsx's "AGPLv3 licensed core"); ensure the wording remains grammatically
identical aside from the license token.

Comment on lines +16 to +19
pwc: {
sector: "Professional services",
outcome: "DocWire powers enterprise data processing workflows requiring high-volume document extraction with full auditability.",
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the actual linkName key for the PwC override.

clientContext is looked up by item.linkName, but src/data/showcaseData.js uses pwc-singapore, not pwc. This branch never matches, so the PwC card silently falls back to showcasesShortInfo and loses its sector label.

Suggested fix
-    pwc: {
+    "pwc-singapore": {
         sector: "Professional services",
         outcome: "DocWire powers enterprise data processing workflows requiring high-volume document extraction with full auditability.",
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pwc: {
sector: "Professional services",
outcome: "DocWire powers enterprise data processing workflows requiring high-volume document extraction with full auditability.",
},
"pwc-singapore": {
sector: "Professional services",
outcome: "DocWire powers enterprise data processing workflows requiring high-volume document extraction with full auditability.",
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containers/usecases/UseCases.jsx` around lines 16 - 19, The PwC override
object key is incorrect: change the 'pwc' key in the overrides map to the actual
linkName 'pwc-singapore' so clientContext lookup (which uses item.linkName) will
match and not fall back to showcasesShortInfo; update the object key where the
PwC override is defined in UseCases.jsx (the entry currently labeled "pwc") to
"pwc-singapore" and keep the existing sector/outcome values intact.

Comment on lines +17 to +22
groupName: "Medical",
icon: BsHospital,
formats: ["DICOM (DCM)", "HL7"],
description:
"Production-tested parsing for healthcare data formats. DICOM scan metadata extraction and HL7 message segment traversal — validated for HIPAA-regulated environments.",
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid publishing an unsupported HIPAA compliance claim.

"validated for HIPAA-regulated environments" reads like a formal compliance attestation. Unless that validation is documented elsewhere, this creates avoidable legal/commercial exposure on the public site. I'd rephrase this to a factual capability statement instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/data/supportedFormatsData.js` around lines 17 - 22, Update the
description for the Medical entry in supportedFormatsData (the object with
groupName "Medical", icon BsHospital, formats ["DICOM (DCM)", "HL7"]) to remove
the compliance attestation "validated for HIPAA-regulated environments" and
replace it with a factual capability statement (e.g., describe supported parsing
features like "parsing and metadata extraction for DICOM and HL7 formats" or
"production-tested parsing for DICOM metadata extraction and HL7 message
traversal") so it conveys functionality without claiming formal regulatory
validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant