@@ -279,18 +278,18 @@ export default function Rfd() {
)
- case 'image':
- return renderToString( )
- default:
- break
- }
-
- return this.baseConverter.convert(node, transform)
- }
+const inlineOverrides: InlineOverrides = {
+ ...baseInlineOverrides,
+ image: InlineImage,
+ anchor: RfdLink,
}
-ad.ConverterFactory.register(new CustomInlineConverter(), ['html5'])
-
-export { ad, attrs }
+export { ad, attrs, inlineOverrides }
diff --git a/package-lock.json b/package-lock.json
index e5ff5b1..e8f4e6e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,8 +12,8 @@
"@floating-ui/react": "^0.17.0",
"@leeoniya/ufuzzy": "^1.0.19",
"@meilisearch/instant-meilisearch": "^0.28.0",
- "@oxide/design-system": "^6.2.1",
- "@oxide/react-asciidoc": "^1.3.0",
+ "@oxide/design-system": "^6.4.1-canary.fec0981",
+ "@oxide/react-asciidoc": "^2.0.0--canary.54.26817409416.0",
"@oxide/remix-auth-rfd": "^0.1.3",
"@oxide/rfd.ts": "^0.14.1",
"@radix-ui/react-accordion": "^1.2.12",
@@ -2416,9 +2416,9 @@
}
},
"node_modules/@oxide/design-system": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/@oxide/design-system/-/design-system-6.2.1.tgz",
- "integrity": "sha512-1QBu1CVLx20AI9QHOo/m7yFslghpYfHhHxa7r/74NV6Ff/RawkUQjl7X+NgFxLyf3jJehWgWBhcycxM+Bw1q3A==",
+ "version": "6.4.1-canary.fec0981",
+ "resolved": "https://registry.npmjs.org/@oxide/design-system/-/design-system-6.4.1-canary.fec0981.tgz",
+ "integrity": "sha512-cdlP8hsIotQP597m4Y2ukBCEa9A/8B/EpA8tSWrabTBKuMM/1qaiRRQRZdx1MgqfyGCPROzYUq7dTDDW3R7Ubg==",
"license": "MPL 2.0",
"dependencies": {
"@floating-ui/react": "^0.27.16",
@@ -2431,7 +2431,7 @@
},
"peerDependencies": {
"@asciidoctor/core": "^3.0.0",
- "@oxide/react-asciidoc": "^1.3.0",
+ "@oxide/react-asciidoc": "^2.0.0--canary.54.26752676803.0",
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
@@ -2452,11 +2452,12 @@
}
},
"node_modules/@oxide/react-asciidoc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@oxide/react-asciidoc/-/react-asciidoc-1.3.0.tgz",
- "integrity": "sha512-0QNKE03z3nh82AjmJD7Gx7uxpEa0Io4bb/3Zlqh7b87c6iyQ99nV1bdiIel/Ja7FfSdC/qqIfmcedxutvKuD7Q==",
+ "version": "2.0.0--canary.54.26817409416.0",
+ "resolved": "https://registry.npmjs.org/@oxide/react-asciidoc/-/react-asciidoc-2.0.0--canary.54.26817409416.0.tgz",
+ "integrity": "sha512-+XXxkZonYG2OFMYixA5aX0BhTMMzEfebs03BOCLEs9WDEIj8zqeVOHSlSc92RFS0aXHp8VDw5fSlWKO7+yrPfw==",
"license": "MPL 2.0",
"dependencies": {
+ "entities": "^6.0.1",
"html-react-parser": "^5.2.6"
},
"peerDependencies": {
@@ -2465,6 +2466,18 @@
"react-dom": ">=18.0.0"
}
},
+ "node_modules/@oxide/react-asciidoc/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/@oxide/remix-auth-rfd": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@oxide/remix-auth-rfd/-/remix-auth-rfd-0.1.5.tgz",
diff --git a/package.json b/package.json
index 15fca74..fe82d91 100644
--- a/package.json
+++ b/package.json
@@ -23,8 +23,8 @@
"@floating-ui/react": "^0.17.0",
"@leeoniya/ufuzzy": "^1.0.19",
"@meilisearch/instant-meilisearch": "^0.28.0",
- "@oxide/design-system": "^6.2.1",
- "@oxide/react-asciidoc": "^1.3.0",
+ "@oxide/design-system": "^6.4.1-canary.fec0981",
+ "@oxide/react-asciidoc": "^2.0.0--canary.54.26817409416.0",
"@oxide/remix-auth-rfd": "^0.1.3",
"@oxide/rfd.ts": "^0.14.1",
"@radix-ui/react-accordion": "^1.2.12",
{authors.map((author, index) => (
-
{author.name}
{index < authors.length - 1 && ', '}
- {' '}
+ {' '}
))}
@@ -301,13 +300,13 @@ export default function Rfd() {
{labels.map((label, index) => (
-
{label.trim()}
{index < labels.length - 1 && ', '}
- {' '}
+ {' '}
))}
diff --git a/app/stores/rfd-preview.ts b/app/stores/rfd-preview.ts
new file mode 100644
index 0000000..f851574
--- /dev/null
+++ b/app/stores/rfd-preview.ts
@@ -0,0 +1,32 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * Copyright Oxide Computer Company
+ */
+import { create } from 'zustand'
+
+import type { RfdListItem } from '~/services/rfd.server'
+
+export interface RfdPreviewState {
+ rfd: RfdListItem
+ position: { left: number; top: number }
+ anchor: HTMLAnchorElement
+}
+
+/**
+ * Holds the RFD link that is currently being previewed on hover. Anchors
+ * rendered inside the document (see the `anchor` inline override) write to
+ * this store, and the single `RfdPreview` overlay subscribes to it. Using a
+ * store rather than DOM event delegation means each link manages its own hover
+ * state through ordinary React handlers.
+ */
+export const useRfdPreviewStore = create<{ preview: RfdPreviewState | null }>(() => ({
+ preview: null,
+}))
+
+export const openRfdPreview = (preview: RfdPreviewState) =>
+ useRfdPreviewStore.setState({ preview })
+
+export const closeRfdPreview = () => useRfdPreviewStore.setState({ preview: null })
diff --git a/app/utils/asciidoctor.tsx b/app/utils/asciidoctor.tsx
index ff89270..f7ac118 100644
--- a/app/utils/asciidoctor.tsx
+++ b/app/utils/asciidoctor.tsx
@@ -5,11 +5,14 @@
*
* Copyright Oxide Computer Company
*/
-import { type Block, type Html5Converter } from '@asciidoctor/core'
-import { InlineConverter, loadAsciidoctor } from '@oxide/design-system/asciidoc'
-import { renderToString } from 'react-dom/server'
+import {
+ inlineOverrides as baseInlineOverrides,
+ loadAsciidoctor,
+} from '@oxide/design-system/asciidoc'
+import { type InlineOverrides } from '@oxide/react-asciidoc'
import { InlineImage } from '~/components/AsciidocBlocks/Image'
+import RfdLink from '~/components/AsciidocBlocks/RfdLink'
const attrs = {
sectlinks: 'true',
@@ -19,27 +22,10 @@ const attrs = {
const ad = loadAsciidoctor({})
-class CustomInlineConverter {
- baseConverter: Html5Converter
-
- constructor() {
- this.baseConverter = new InlineConverter()
- }
-
- convert(node: Block, transform: string) {
- switch (node.getNodeName()) {
- case 'inline_image':
- return renderToString(