Skip to content

Commit 1c8af10

Browse files
DOC-5191: Update local preview assets (#203)
* Update local preview assets * Might as well add the latest attributes
1 parent 0eed0bc commit 1c8af10

File tree

5 files changed

+207
-77
lines changed

5 files changed

+207
-77
lines changed

lib/icon-macro.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* This macro relies on the material-icons font and the lucide icons font being loaded in UI bundle.
3+
*
4+
* @example Material Icon
5+
* icon:material:menu-open[]
6+
*
7+
* @example Lucide Icon
8+
* icon:boom-box[]
9+
*/
10+
function inlineIconMacro() {
11+
return function () {
12+
this.process((parent, target, attrs) => {
13+
if (target.startsWith("material:")) {
14+
iconTarget = target
15+
.replace("material:", "")
16+
.trim()
17+
.replace("-", "_");
18+
return this.createInlinePass(
19+
parent,
20+
`<i ${htmlAttrs(attrs, "material-icons")}>${iconTarget}</i>` + renderName(attrs?.name)
21+
);
22+
} else {
23+
iconTarget = target
24+
.replace("lucide:", "")
25+
.trim()
26+
return this.createInlinePass(
27+
parent,
28+
`<i ${htmlAttrs(attrs, `icon-${iconTarget}`)}></i>` + renderName(attrs?.name)
29+
);
30+
}
31+
});
32+
};
33+
}
34+
35+
function renderName(name) {
36+
if (!name) return "";
37+
return ` <b>${name}</b>`;
38+
}
39+
40+
function htmlAttrs({ size, role, alt, title, ariaLabel, $positional = [] }, klass) {
41+
const [posSize] = $positional;
42+
return [
43+
(size || posSize) && `style="font-size: ${(size || posSize).replace("px", "").trim()}px;"`,
44+
(role || klass) && `class="${[klass, role].filter(Boolean).join(" ")}"`,
45+
title && `title="${title}"`,
46+
(alt || ariaLabel) && `aria-label="${alt || ariaLabel}" role="img"`,
47+
!(alt || ariaLabel) && "aria-hidden='true'",
48+
]
49+
.filter(Boolean)
50+
.join(" ");
51+
}
52+
53+
/**
54+
* @param { import("@asciidoctor/core/types").Asciidoctor.Extensions.Registry } registry
55+
* @param context
56+
*/
57+
function register(registry) {
58+
registry.inlineMacro("icon", inlineIconMacro());
59+
}
60+
61+
module.exports.register = register;

lib/svg-macro.js

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ const logger = require("@antora/logger")("asciidoctor:svg-macro");
55
* svg:ROOT:ui/icons/vector.svg[]
66
*/
77
function inlineSvgMacro({ contentCatalog, file }) {
8+
/**
9+
* @this { import("@asciidoctor/core/types").Asciidoctor.Extensions.InlineMacroProcessorInstance }
10+
*/
811
return function () {
912
this.process((parent, target, attrs) => {
10-
svgContent = getSvgContent(target, file, contentCatalog);
13+
const svgContent = getSvgContent(target, file, contentCatalog);
1114
if (!svgContent) return;
15+
const html = svgContent.replace("<svg", `<svg ${htmlAttrs(attrs, "inline-block")}`);
1216
return this.createInlinePass(
1317
parent,
14-
svgContent.replace("<svg", `<svg ${htmlAttrs(attrs)}`)
18+
insertLink(insertTitle(html, attrs.title), attrs.link, attrs.window) + renderName(attrs.name)
1519
);
1620
});
1721
};
@@ -22,54 +26,49 @@ function inlineSvgMacro({ contentCatalog, file }) {
2226
* svg::home:diagrams/graphic.svg[alt="My Graphic"]
2327
*/
2428
function blockSvgMacro({ contentCatalog, file }) {
29+
/**
30+
* @this { import("@asciidoctor/core/types").Asciidoctor.Extensions.BlockMacroProcessorInstance }
31+
*/
2532
return function () {
2633
this.process((parent, target, attrs) => {
27-
svgContent = getSvgContent(target, file, contentCatalog);
34+
const svgContent = getSvgContent(target, file, contentCatalog);
2835
if (!svgContent) return;
29-
const svgHtmlAttrs = htmlAttrs({ ...attrs, role: undefined });
30-
const containerHtmlAttrs = attrs.role
31-
? `class="imageblock ${attrs.role}"`
32-
: 'class="imageblock"';
33-
const html =
34-
`<div ${containerHtmlAttrs}><div class="content">` +
35-
svgContent.replace("<svg", `<svg ${svgHtmlAttrs}`) +
36-
"</div></div>";
37-
return this.createBlock(parent, "pass", html);
36+
// create an image block and convert it to an html string
37+
const imageBlockNode = this.createImageBlock(parent, { ...attrs, target});
38+
imageBlockNode.setId(attrs.id);
39+
const imageBlockContent = imageBlockNode.convert();
40+
// replace the <img> tag with the svg content
41+
const svg = svgContent.replace("<svg", `<svg ${htmlAttrs({ ...attrs, role: undefined, id: undefined })}`);
42+
const svgBlockContent = imageBlockContent.replace(/<img [^>]*>/, svg);
43+
// return a passthrough block with the html content
44+
return this.createPassBlock(parent, svgBlockContent);
3845
});
3946
};
4047
}
4148

42-
/**
43-
* This macro relies on the material-icons font being loaded in UI bundle.
44-
*
45-
* @example Material Icon
46-
* icon:material-icons:menu_open[]
47-
*
48-
* @example Embedded SVG
49-
* icon:ROOT:ui/icons/vector.svg[]
50-
*/
51-
function inlineIconMacro({ contentCatalog, file }) {
52-
return function () {
53-
this.process((parent, target, attrs) => {
54-
if (target.startsWith("material-icons")) {
55-
iconTarget = target
56-
.replace("material-icons:", "")
57-
.trim()
58-
.replace("-", "_");
59-
return this.createInlinePass(
60-
parent,
61-
`<i ${htmlAttrs(attrs, "material-icons icon")}>${iconTarget}</i>`
62-
);
63-
} else {
64-
svgContent = getSvgContent(target, file, contentCatalog);
65-
if (!svgContent) return;
66-
return this.createInlinePass(
67-
parent,
68-
svgContent.replace("<svg", `<svg ${htmlAttrs(attrs, "svg icon")}`)
69-
);
70-
}
71-
});
72-
};
49+
function insertTitle(svgContent, title) {
50+
if (!title) return svgContent;
51+
const svgMatch = svgContent.match(/<svg[^>]*>/);
52+
const titleTag = `<title>${title}</title>`;
53+
const svgOpenTag = svgMatch[0];
54+
const insertionIndex = svgContent.indexOf(svgOpenTag) + svgOpenTag.length;
55+
const updatedSvgContent =
56+
svgContent.slice(0, insertionIndex) +
57+
titleTag +
58+
svgContent.slice(insertionIndex);
59+
60+
return updatedSvgContent;
61+
}
62+
63+
function insertLink(svgContent, href, target) {
64+
if (!href) return svgContent;
65+
const targetAttr = target ? ` target="${target}"` : "";
66+
return `<a href="${href}"${targetAttr}>${svgContent}</a>`;
67+
}
68+
69+
function renderName(name) {
70+
if (!name) return "";
71+
return ` <b>${name}</b>`;
7372
}
7473

7574
function getSvgContent(target, file, contentCatalog) {
@@ -84,14 +83,15 @@ function getSvgContent(target, file, contentCatalog) {
8483
return svgContent;
8584
}
8685

87-
function htmlAttrs({ width, height, role, alt, title }, klass = "svg") {
86+
function htmlAttrs({ id, width, height, role, alt, ariaLabel, $positional = [] }, klass) {
87+
const [posAlt, posWidth, posHeight] = $positional;
8888
return [
89-
width && `width="${width}"`,
90-
height && `height="${height}"`,
91-
role ? `class="${klass} ${role}"` : `class="${klass}"`,
92-
alt && `aria-label="${alt}"`,
93-
title && `aria-label="${title}"`,
94-
(alt || title) && 'role="img"',
89+
id && `id="${id}"`,
90+
(width || posWidth) && `width="${width || posWidth}"`,
91+
(height || posHeight) && `height="${height || posHeight}"`,
92+
(role || klass) && `class="${[klass, role].filter(Boolean).join(" ")}"`,
93+
(alt || ariaLabel || posAlt) && `aria-label="${alt || ariaLabel || posAlt}" role="img"`,
94+
!(alt || ariaLabel || posAlt) && "aria-hidden='true'",
9595
]
9696
.filter(Boolean)
9797
.join(" ");
@@ -104,7 +104,6 @@ function htmlAttrs({ width, height, role, alt, title }, klass = "svg") {
104104
function register(registry, context) {
105105
registry.inlineMacro("svg", inlineSvgMacro(context));
106106
registry.blockMacro("svg", blockSvgMacro(context));
107-
registry.inlineMacro("icon", inlineIconMacro(context));
108107
}
109108

110109
module.exports.register = register;

lib/tailwind-processor.js

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,79 @@
11
"use strict";
22

33
const { execSync } = require("child_process");
4+
const fs = require("fs");
5+
const path = require("path");
6+
7+
function updateTailwindConfig(configPath, outputDir, logger) {
8+
try {
9+
// Read the existing config
10+
const configContent = fs.readFileSync(configPath, 'utf8');
11+
12+
// Create a temporary file with updated content
13+
const updatedContent = configContent.replace(
14+
/content:\s*\[.*?'\.\/build\/site\/.*?'\]/s,
15+
`content: ['${outputDir}/**/*.{html,js}']`
16+
);
17+
18+
const tempConfigPath = path.join(path.dirname(configPath), 'tailwind.temp.js');
19+
fs.writeFileSync(tempConfigPath, updatedContent);
20+
logger.info(`Created temporary Tailwind config with updated output dir: ${outputDir}`);
21+
22+
return tempConfigPath;
23+
} catch (error) {
24+
logger.error(`Error updating Tailwind config: ${error.message}`);
25+
throw error;
26+
}
27+
}
28+
29+
function cleanup(tempConfigPath, logger) {
30+
try {
31+
if (fs.existsSync(tempConfigPath)) {
32+
fs.unlinkSync(tempConfigPath);
33+
logger.info('Cleaned up temporary Tailwind config');
34+
}
35+
} catch (error) {
36+
logger.warn(`Error cleaning up temporary config: ${error.message}`);
37+
}
38+
}
439

540
module.exports.register = (context) => {
641
context.once("sitePublished", ({ playbook }) => {
7-
const logger = context.getLogger('tailwind-processor-extension')
42+
const logger = context.getLogger('tailwind-processor-extension');
843
const outputDir = playbook?.output?.dir || "build/site";
44+
945
logger.info("Building Tailwind");
10-
var configPath = execSync(`find ${outputDir} -name tailwind.config.js`)
11-
.toString()
12-
.trim();
13-
var cssPath = execSync(`find ${outputDir} -name site*.css`)
14-
.toString()
15-
.trim();
16-
logger.info(
17-
`npm run tailwindcss --tailwind-config-path=${configPath} --css-path=${cssPath}`
18-
);
19-
execSync(
20-
`npm run tailwindcss --tailwind-config-path=${configPath} --css-path=${cssPath}`,
21-
{ stdio: "inherit" }
22-
);
23-
logger.info("Tailwind Build Successful");
46+
47+
try {
48+
// Find the config and CSS files
49+
const configPath = execSync(`find ${outputDir} -name tailwind.config.js`)
50+
.toString()
51+
.trim();
52+
53+
const cssPath = execSync(`find ${outputDir} -name site*.css`)
54+
.toString()
55+
.trim();
56+
57+
// Create temporary config with updated output directory
58+
const tempConfigPath = updateTailwindConfig(configPath, outputDir, logger);
59+
60+
// Run Tailwind with the temporary config
61+
logger.info(
62+
`Running Tailwind with config: ${tempConfigPath} and CSS: ${cssPath}`
63+
);
64+
65+
execSync(
66+
`npm run tailwindcss --tailwind-config-path=${tempConfigPath} --css-path=${cssPath}`,
67+
{ stdio: "inherit" }
68+
);
69+
70+
// Clean up
71+
cleanup(tempConfigPath, logger);
72+
73+
logger.info("Tailwind Build Successful");
74+
} catch (error) {
75+
logger.error(`Tailwind build failed: ${error.message}`);
76+
throw error;
77+
}
2478
});
2579
};

local-preview-playbook.yml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ runtime:
33
failure_level: warn
44
git:
55
# ensure_git_suffix: false # Enable if necessary -- some git services don’t recognize the URL if it contains the .git extension.
6-
fetch_concurrency: 10
6+
fetch_concurrency: 8
77

88
site:
99
title: DataStax Docs
@@ -15,13 +15,17 @@ content:
1515
sources:
1616
- url: .
1717
branches: HEAD
18+
- url: https://github.com/riptano/docs-common.git
19+
# To incorporate the currently-checked-out branch (HEAD) from your _local_ docs-common clone:
20+
# - url: ../docs-common
21+
# branches: HEAD
1822

1923
antora:
2024
extensions:
21-
- '@antora/atlas-extension'
2225
- '@antora/collector-extension'
2326
- lib/assets-processor.js
2427
- lib/tailwind-processor.js
28+
- '@antora/atlas-extension'
2529
- id: unlisted-pages
2630
enabled: true
2731
require: lib/unlisted-pages-extension.js
@@ -31,10 +35,11 @@ antora:
3135
asciidoc:
3236
extensions:
3337
- '@asciidoctor/tabs'
38+
- asciidoctor-external-callout
39+
- asciidoctor-kroki
40+
- lib/icon-macro.js
3441
- lib/remote-include-processor.js
3542
- lib/svg-macro.js
36-
- asciidoctor-kroki
37-
- asciidoctor-external-callout
3843
attributes:
3944
# BUILT-IN ATTRIBUTES
4045
# allow-uri-read: '' # Quality-of-life benefit for IntelliJ users. CAUTION: Opens the door to malicious code insertion - must remain disabled in prod build environment.
@@ -51,13 +56,19 @@ asciidoc:
5156
example-caption: false
5257
figure-caption: false
5358
table-caption: false
59+
table-stripes: 'hover'
5460
xrefstyle: short
5561
# CUSTOM ATTRIBUTES
5662
company: 'DataStax'
5763
astra_db: 'Astra DB'
5864
astra_stream: 'Astra Streaming'
65+
astra-stream: 'Astra Streaming' # AIM: Once all instances of astra_stream are removed, keep only the astra-stream attribute.
5966
astra_ui: 'Astra Portal'
6067
astra_cli: 'Astra CLI'
68+
astra-cli: 'Astra CLI' # AIM: Once all instances of astra_cli are removed, keep only the astra-cli attribute.
69+
scb: 'Secure Connect Bundle (SCB)'
70+
scb-short: 'SCB'
71+
scb-brief: 'Secure Connect Bundle'
6172
astra-streaming-examples-repo: 'https://raw.githubusercontent.com/datastax/astra-streaming-examples/master'
6273
luna-streaming-examples-repo: 'https://raw.githubusercontent.com/datastaxdevs/luna-streaming-examples/main'
6374
support_url: 'https://support.datastax.com'
@@ -71,6 +82,12 @@ asciidoc:
7182
classic_cap: 'Classic'
7283
serverless: 'serverless'
7384
serverless_cap: 'Serverless'
85+
py-client-api-ref-url: 'xref:astra-api-docs:ROOT:attachment$python-client-1x/astrapy'
86+
ts-client-api-ref-url: 'xref:astra-api-docs:ROOT:attachment$typescript-client-1x'
87+
java-client-api-ref-url: 'xref:astra-api-docs:ROOT:attachment$java-client-1x'
88+
py-client-api-ref-url-2x: 'xref:astra-api-docs:ROOT:attachment$python-client/astrapy'
89+
ts-client-api-ref-url-2x: 'xref:astra-api-docs:ROOT:attachment$typescript-client'
90+
java-client-api-ref-url-2x: 'xref:astra-api-docs:ROOT:attachment$java-client'
7491
# Antora Atlas
7592
primary-site-url: https://docs.datastax.com/en
7693
primary-site-manifest-url: https://docs.datastax.com/en/site-manifest.json

package.json

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414
},
1515
"dependencies": {
1616
"@antora/atlas-extension": "^1.0.0-alpha.2",
17-
"@antora/collector-extension": "^1.0.0-alpha.3",
17+
"@antora/collector-extension": "^1.0.1",
1818
"@asciidoctor/tabs": "^1.0.0-beta.6",
19-
"antora": "3.2.0-alpha.4",
20-
"asciidoctor-external-callout": "~1.2.1",
21-
"asciidoctor-kroki": "~0.18.1",
22-
"csv-parser": "^3.0.0",
19+
"antora": "3.2.0-alpha.8",
20+
"asciidoctor-external-callout": "^1.2.1",
21+
"asciidoctor-kroki": "^0.18.1",
22+
"linkinator": "^5.0.2",
2323
"lodash": "^4.17.21",
24-
"npm-run-all": "^4.1.5",
25-
"tailwindcss": "^3.3.5"
24+
"tailwindcss": "^3.3.3"
2625
}
2726
}

0 commit comments

Comments
 (0)