Skip to content

docs(content): complete public frontend workflows for the Content Engine - #896

Open
aXenDeveloper wants to merge 26 commits into
canaryfrom
claude/vitnode-content-engine-docs-nhbqpv
Open

aXenDeveloper wants to merge 26 commits into
canaryfrom
claude/vitnode-content-engine-docs-nhbqpv

Conversation

@aXenDeveloper

Copy link
Copy Markdown
Owner
  • Add Public frontend overview, Viewer permissions guide/reference,
    useContentPublicWrite reference and Threaded replies on the frontend.
  • Rewrite the public edit guide around a complete, typechecked baseline
    (route, messages, 401/403/404/unexpected states, versions, conflicts,
    pending proposals, invalidation) with real screenshots.
  • Point reports, pages, lists and the write API reference at the new
    pages; fix pendingComponent claims that predate navigation progress.

fix(content): batch useContentPermissions within the 50-id route limit

The hook sent every id in one request, so a thread with more than 50
visible replies got 400 and lost all Edit/Report buttons. It now dedupes
ids, sends batches of 50 as separate queries (at most three in flight),
merges answers by id and exposes isError.

fix(content): keep microseconds in thread cursors

The cursor carried a millisecond Date while Postgres stores microseconds,
so every page repeated the previous page's last top-level reply. Encode
the column's own ::text and cast it back, as shared pagination does.

fix(forum): edit topics with useContentPublicWrite

Use the core hook so the edit page shows the documented conflict UI
(Keep my version), and keep the form's defaults in step after a save so
AutoForm no longer puts the old title back.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J

@github-actions github-actions Bot added the 📖 Documentation Documentation changes label Oct 21, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T09:54:13.321328Z 72d39f0 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

React Doctor found 10 new issues in 7 files · 10 warnings · score 74 / 100 (Needs work) · 0 fixed · vs canary

10 warnings

src/pages/articles-page.tsx

  • ⚠️ L84 Role used instead of HTML tag prefer-tag-over-role

src/pages/desk-page.tsx

  • ⚠️ L120 Heading has no content heading-has-content
  • ⚠️ L243 Heading has no content heading-has-content

src/pages/desks-page.tsx

  • ⚠️ L88 Duplicated JSX structure duplicate-jsx-subtree
  • ⚠️ L92 Heading has no content heading-has-content

src/pages/letter-edit-page.tsx

  • ⚠️ L165 Heading has no content heading-has-content

src/pages/letter-new-page.tsx

  • ⚠️ L113 Heading has no content heading-has-content

src/pages/letters-page.tsx

  • ⚠️ L101 Heading has no content heading-has-content
  • ⚠️ L154 Role used instead of HTML tag prefer-tag-over-role

src/pages/zones-page.tsx

  • ⚠️ L330 Locale/timezone formatting during render no-locale-format-in-render

Reviewed by React Doctor for commit 72d39f0. See inline comments for fixes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f5b84d978

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


const nodeSelection = {
createdAt: columns.createdAt,
createdAtText: sql<string>`${columns.createdAt}::text`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize cursor timestamps independently of DateStyle

When PostgreSQL is configured with a non-ISO DateStyle (for example SQL, DMY), timestamp::text emits a value such as 21/10/2026 12:00:00, but decodeCursor accepts only the ISO-shaped regex. A cursor generated by the first page is therefore rejected on the next request, after_ is omitted, and pagination restarts from the first page indefinitely. Use a fixed, DateStyle-independent representation that preserves microseconds rather than the session-dependent text cast.

Useful? React with 👍 / 👎.

@aXenDeveloper
aXenDeveloper force-pushed the claude/vitnode-content-engine-docs-nhbqpv branch from 3f5b84d to 76124c5 Compare October 23, 2026 17:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 76124c54e0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +187 to +188
const TIMESTAMP_TEXT =
/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|[+-]\d{2}(?::?\d{2})?)?$/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject impossible timestamp cursor values before casting

When a client supplies a base64url cursor containing a shape-valid but impossible timestamp such as 2026-99-99 12:00:00, this regex accepts it and after_ asks PostgreSQL to cast it, which raises a datetime error and turns the public thread request into a 500. The previous Date parsing rejected such values before querying; validate the actual timestamp value or otherwise handle cast failures so malformed cursors cannot trigger server errors.

Useful? React with 👍 / 👎.

Comment on lines +165 to +168
queries: contentPermissionBatches(ids).map(batch => ({
enabled: !session.isPending,
queryFn: async () => await limit(async () => await fetch(batch)),
queryKey: [...queryKey, "permissions", { ids: batch, userId }],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cancel queued permission requests when the session changes

When more than 150 IDs leave batches waiting in this limiter and the session changes before they receive a slot, each query retains a key containing the old userId, but fetch(batch) runs later with the new session cookie. The response is therefore cached under the wrong visitor's key; because the app query client disables refetch-on-mount, returning to that identity can reuse incorrect Edit/Report flags. Make queued work cancellation-aware or ensure the request is dispatched only while its captured principal still matches the active session.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 219e1fa1c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

>
<div className="flex flex-wrap items-center gap-2">
<AutoFormSubmitButton>{t("save")}</AutoFormSubmitButton>
<Button onClick={onCancel} type="button" variant="ghost">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Disable Cancel while a comment save is pending

On a slow save, Cancel remains enabled and unmounts the editor without cancelling its PATCH request. If the member reopens Edit and starts typing before that request finishes, the original submission's onSaved callback still calls setEditing(null) in CommentItem, closing the new editor and discarding its unsaved text. AutoForm disables the submit button, not this custom Cancel button. Bind Cancel to the form's submitting state so conflicting actions cannot run, as required by AGENTS.md.

AGENTS.md reference: AGENTS.md:L45-L45

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d34307ce79

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

<Composer
articleId={articleId}
// A fresh key gives the next comment an empty editor.
key={composerKey}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope the comment composer instance to the article

When a reader types an unsent comment and navigates client-side to another article through LatestArticles, composerKey remains unchanged. The /news/:slug route renders its page without a parameter-dependent key, so the existing composer and its dirty form state survive while articleId changes. Submitting then posts the previous article's draft under the newly opened article. Include articleId in the composer key, or key the comment section by article, so form state cannot cross article boundaries.

Useful? React with 👍 / 👎.

claude and others added 22 commits October 25, 2026 09:10
- Add Public frontend overview, Viewer permissions guide/reference,
  useContentPublicWrite reference and Threaded replies on the frontend.
- Rewrite the public edit guide around a complete, typechecked baseline
  (route, messages, 401/403/404/unexpected states, versions, conflicts,
  pending proposals, invalidation) with real screenshots.
- Point reports, pages, lists and the write API reference at the new
  pages; fix pendingComponent claims that predate navigation progress.

fix(content): batch useContentPermissions within the 50-id route limit

The hook sent every id in one request, so a thread with more than 50
visible replies got 400 and lost all Edit/Report buttons. It now dedupes
ids, sends batches of 50 as separate queries (at most three in flight),
merges answers by id and exposes isError.

fix(content): keep microseconds in thread cursors

The cursor carried a millisecond Date while Postgres stores microseconds,
so every page repeated the previous page's last top-level reply. Encode
the column's own ::text and cast it back, as shared pagination does.

fix(forum): edit topics with useContentPublicWrite

Use the core hook so the edit page shows the documented conflict UI
(Keep my version), and keep the form's defaults in step after a save so
AutoForm no longer puts the old title back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Rebuild the beginner path on one minimal newsroom article (title, slug,
body): First content type, Drafts & publishing, Public API, Content list
and Content page, each continuing the previous page and ending with a
check of the result. Member forms, permissions, reports, comments and
replies continue the same example, with complete files and real
request/response examples.

- Reorganize the sidebar into Getting started, Public content, Member
  content, Interactions, Organization, Moderation, Content features,
  Editorial, Customization, Deployment and Reference, with short titles.
- Fold Public frontend into the Introduction; split Editorial into
  Revisions, Previews and Scheduling; add Permissions API.
- Replace screenshots with captures of the documented example and drop
  the unused ones.
- Wrap long inline code on phones so docs pages never scroll sideways.
- Give a required rich text field an empty document by default, so the
  AdminCP create dialog can submit it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
…CP forms

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Keep First content type, Drafts & publishing, Public API, Content list
  and Content page together, and move Embedded list after them. Embedded
  list now adds a server-rendered Latest articles box that reuses
  articlesQueryOptions.
- Rewrite Relations on a minimal newsroom.category with its model, table
  export, registration, references map and migration; move to-many
  relations, groups, repeatables and mixed id strategies to Advanced
  fields.
- Tell drafts and pending approval apart: a plain create.status "draft"
  never opens a submission, so the create form and the comment composer
  now say "draft" and "waiting for a moderator" separately and only say
  "posted" for a public record. Approvals documents the states.
- Focus Edit form on loading, refusals, saving with the version, form
  defaults, invalidation and conflicts; move proposals and rejection
  notices to Approval notices, built on the Forum plugin.
- Split comments into Comments, Comment editing and Replies, each with
  its own result, including loading, error and retry states and the
  last-write-wins behavior without editorial.
- Make Reports work from Content page alone, with its own permissions
  wrapper, verified on a staff-written article.
- Replace screenshots that no longer matched with new captures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
…m their prerequisites

- Relations needs only First content type: the check now creates a
  category, assigns it and deletes it in the AdminCP, with the list column
  as a required step. Reading the category through the public API moved
  to an optional section that names its prerequisites, keeps the other
  publicApi options and says that only the related id is exposed.
- Comments no longer requires member article writing: the article needs
  its public API and page, the comment type brings its own author and
  publicWrite, and TanStack Query has its install commands inline. The
  check uses Welcome to the newsroom, and repeated explanations point to
  one outcome table.
- Approval notices read the server's approval only. The example shows
  its imports and types, drops the Forum's ?submitted=1 flag and explains
  why a URL must not decide a notice.
- Recapture the Relations screenshots on a First content type article and
  the comment section on Welcome to the newsroom.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
The edit page showed "Waiting for a moderator" whenever the URL carried
?submitted=1, even on a published topic or a plain draft with nothing
pending. The create page added that flag, but the edit route already
returns the pending submission, so the flag added nothing.

- ApprovalNotice reads only `approval`: pending create and pending edit
  need their exact status and kind, rejections keep the reason, and
  `approval: null` renders nothing whatever the status.
- Drop the submitted flag from topicEditHref, the edit route's search
  and the create redirect. Old links with ?submitted=1 still open; the
  parameter is ignored.
- After creating, only a published topic with a slug opens its public
  page; a pending or draft topic opens its edit page.
- Align the Approval notices guide with the Forum code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Newsroom, the plugin the Content Engine tutorial builds, now carries
everything the example plugin demonstrated: stories with files,
scheduling, live editing and an AI teaser action, localized explainers
and bulletins, uuid tags and bigint events, a desk container tree for
letters to the editor, block pages, the settings page with widget zones
and its blocks, a category moderation scope, the AdminCP overview page
and the routing demo pages.

The example plugin is removed from the workspace and both apps, and one
migration drops its tables and creates the newsroom ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
The staff permission editor loads its label namespaces in chunks of
MAX_NAMESPACES and merged them with Object.assign. Two chunks that each
carried part of one plugin's root object replaced each other, so a
plugin's title fell back to its id and a moderation scope label showed
as the scope id. Merge the chunks deeply instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Rewrite the Content Engine, moderation, widgets, events, AI and search
pages that used the removed example plugin so their code, ids, URLs and
tables come from plugins/newsroom. Retake the 17 screenshots that showed
example-plugin screens, now on seeded newsroom data, and correct their
alt texts. Also tidy the ported zones and explainer pages and the
newsroom README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Rewrites the beginner lessons (setup to AdminCP) around one plugin and
corrects the API mismatches the audit found in queue, events, email
templates, storage and widgets. Adds a Learn group to the sidebar,
shortens titles, splits the visual editor page, and repairs broken
anchors.

Fixes found while validating the examples:
- Bodiless DELETE requests answered 500 on TanStack Start apps: Hono's
  bodyLimit rebuilt the request with new Request(request, init), which
  throws on that runtime. The API now uses its own body limit middleware.
- email.tailwindConfig in the API config never reached the default
  email template.
- The newsroom plugin gains /newsroom/pages/:slug, which renders a page
  record's widgets, and labels for its widgets moderator permission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Cron is a site-notes how-to that uses the real buildCron options and
  logger levels, explains the production CRON_SECRET refusal and the
  Bearer requirement, and lists the adapters' real behaviour.
- Notifications, websocket and updates pages match source; rooms move
  to their own websocket page.
- Pagination and search are rebuilt on the site_notes table.
- Debugging gains a real Debug Panel screenshot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Users splits into Current user, Profile fields, Avatars and Manage
  users; the roles URL and labels match the AdminCP.
- Redis documents the in-memory fallback without REDIS_URL and the
  separate REDIS_PASSWORD; auth lists every cookie option.
- SSO, passkeys and captcha examples match source, including the state
  cookie round trip and Discord's unverified-email refusal.
- Real screenshots of the roles list and the Moderator CP approval
  queue and submission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Configuration is a reference with an entry point and option tables for
  buildConfig, createVitNodeStart and vitnode().
- CLI pages explain that db:migrate runs the legacy vitnode migrate and
  show real plugin list and validate output.
- Swagger is on in development only unless docs.enabled is set.
- Dashboard widgets is a site-notes how-to with real data and settings;
  contribution lists the checks CI actually runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
The site-notes Notes widget from the tutorial, built as documented and
placed on the AdminCP dashboard; its settings form was checked too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- AI actions splits into a first-action tutorial plus action options,
  streaming and errors; fields-and-editor splits into field
  suggestions, custom UI, Quick Ask and translations. Examples use the
  installed ai@7 API and the real forum permission module.
- Search pages document the real reference fields and HeaderSearch;
  Elasticsearch gains prerequisites and a check step.
- Mobile navigation gains real phone screenshots of the bottom bar and
  the Menu drawer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
…i18n

- Routing becomes an overview with a task map, plus new pages: Add a
  route (a /site-notes/notes/:id tutorial, built and checked on the
  plugin), Route module, Layouts, URL parameters and Protected routes.
- Localized URLs splits into a basic page and an advanced one (domains,
  proxies, language detection, redirects, hreflang).
- Fetcher, server functions, cache, i18n, performance and deployment
  pages match source and use the site-notes plugin throughout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Content zones and editable pages split into the smallest tasks: render
  one zone, several zones, restrict widgets, make a page editable (a
  site-notes how-to, built and checked end to end with a real save
  screenshot), custom loader and saving layouts. Duplicated excerpts,
  QA checklists and design history are gone; labels match the editor.
- Widget pages fix registration, layout-area values, sample data and
  status codes.
- Built-in events passes pluginId when a listener queues work, replaces
  the cache example and uses the real logger levels; the custom event
  adapter runs the local listeners before forwarding to Redis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Regenerated by vitnode dev after the newsroom plugin gained the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Regression tests for the two fixes: a streamed or bodiless request on a
non-global Request no longer answers 500, and the API config's
email.tailwindConfig reaches the template props.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
- Database: address the generated Compose service and project
  (docker compose -p my-vitnode-vitnode-dev exec -T database) instead of
  a container name the generator renames, from the workspace root.
- Add a route: install both @tanstack/react-query and
  @tanstack/react-router, matching the app's version ranges.
- First widget: register only the callout it teaches, allow only
  core widgets and the callout, keep existing registrations, add the
  page type's strings, and drop an undeclared AdminNavPluginSource.
- Editable pages: start the config from the Plugin page state, explain
  merging permissionStaff, label the plugin title, and recapture the
  screenshot from that state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
The sidebar and the docs footer's "Next up" card already link the
following page. Single-link Next step sections are removed; sections
with several useful links are kept as Related. The docs skill and
AGENTS.md now say not to add Next step endings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
claude and others added 4 commits October 25, 2026 09:15
The buttons now show only the provider's name under a Continue with
heading, so the setup checks say to press the Google, Discord or
Facebook button, and the Google image prompt shows the two-column page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
Show a moderator permission next to the admin one, and a public route
that guards it with assertStaffPermission and type moderator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yePNEqnbDm9BZVuNkWU5J
@aXenDeveloper
aXenDeveloper force-pushed the claude/vitnode-content-engine-docs-nhbqpv branch from 45aa3a5 to 72d39f0 Compare October 25, 2026 09:52

<div
className="flex flex-col gap-3 md:flex-row md:items-center"
role="search"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/prefer-tag-over-role (warning)

Screen reader users get more reliable semantics from <search> than role="search", so use <search> instead.

Fix → Use the matching HTML element when one exists so browsers and assistive tech get native semantics.

Docs

<Empty className="border">
<EmptyHeader>
<EmptyMedia variant="icon">
<MessagesSquareIcon aria-hidden="true" />
</EmptyMedia>
<EmptyTitle render={<h3 />}>{t("empty_board.title")}</EmptyTitle>
<EmptyDescription>{t("empty_board.desc")}</EmptyDescription>
<EmptyTitle render={<h3 />}>{t("empty_desk.title")}</EmptyTitle>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/heading-has-content (warning)

Blind users can't use this heading to navigate because screen readers skip it empty, so add text, aria-label, or aria-labelledby.

Fix → Put readable text in every heading.

Docs

<EmptyMedia variant="icon">
<FolderTreeIcon aria-hidden="true" />
</EmptyMedia>
<EmptyTitle render={<h2 />}>{t("new.no_desks.title")}</EmptyTitle>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/heading-has-content (warning)

Blind users can't use this heading to navigate because screen readers skip it empty, so add text, aria-label, or aria-labelledby.

Fix → Put readable text in every heading.

Docs

This branch has not been deployed

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

Labels

📖 Documentation Documentation changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants