Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion prototypes/docusaurus/src/pages/examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const evaluationPaths = [
eyebrow: 'Upgrade path',
title: 'Move from OSS to Pro',
description:
'If your current app needs more SSR throughput or RSC support, compare OSS and Pro before adding the Pro package.',
'If your current app needs more SSR throughput or RSC support, compare OSS and Pro, then evaluate Pro without a token before production licensing.',
href: docsRoutes.ossVsPro,
cta: 'Compare OSS and Pro',
},
Expand Down
19 changes: 18 additions & 1 deletion prototypes/docusaurus/src/pages/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@
}

.upgradeGrid {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: repeat(3, minmax(0, 1fr));
}

.flowGrid {
Expand Down Expand Up @@ -316,6 +316,23 @@
margin-bottom: 0.7rem;
}

.licenseStrip {
display: flex;
flex-wrap: wrap;
gap: 0.35rem 0.5rem;
align-items: baseline;
margin-bottom: 1rem;
padding: 0.85rem 0.95rem;
border: 1px solid rgba(9, 105, 218, 0.3);
border-left: 4px solid var(--ifm-color-primary);
border-radius: 8px;
background: var(--site-surface);
}

.licenseStrip strong {
color: var(--ifm-color-primary-dark);
}

.inlineCode {
display: block;
margin: 0 0 1rem;
Expand Down
23 changes: 19 additions & 4 deletions prototypes/docusaurus/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const personaPaths = [
{
title: 'Already on OSS and need more performance',
description:
'Compare OSS and Pro first, then upgrade only when higher-throughput SSR, RSC, or support is worth it.',
'Compare OSS and Pro first, then evaluate Pro without a token before buying a production license.',
href: docsRoutes.ossVsPro,
cta: 'Compare OSS and Pro',
},
Expand Down Expand Up @@ -57,7 +57,7 @@ const recommendedFlows = [
{
title: 'When OSS is no longer enough',
summary:
'Pro is an upgrade tier, not a separate product. Compare first, then add it when the extra SSR throughput or guided support matters.',
'Pro is an upgrade tier, not a separate product. Evaluate it in development, test, CI/CD, and staging before you need a production license.',
command: 'bundle add react_on_rails_pro',
href: docsRoutes.proUpgrade,
cta: 'Open the upgrade guide',
Expand Down Expand Up @@ -379,7 +379,7 @@ function HeroSection() {
</div>
<p className={styles.panelNote}>
Already on OSS? Start with the comparison guide, then use the upgrade guide if you
need Pro.
need Pro. No token is required for non-production evaluation.
</p>
</div>
</div>
Expand Down Expand Up @@ -444,6 +444,11 @@ function UpgradeSection() {
<p className={styles.sectionEyebrow}>OSS to Pro</p>
<h2>Upgrade when you're ready.</h2>
</div>
<div className={styles.licenseStrip}>
<strong>Friendly license model:</strong> evaluate Pro without a token in development,
test, CI/CD, and staging. Production deployments require a paid license.
<Link href="https://pro.reactonrails.com/">See pricing and sign up</Link>
</div>
<div className={styles.upgradeGrid}>
<article className={styles.migrationCard}>
<h3>1. Compare OSS and Pro</h3>
Expand All @@ -459,12 +464,22 @@ function UpgradeSection() {
<h3>2. Upgrade to Pro</h3>
<p>
Once the comparison says Pro is worth it, follow the upgrade guide and add the Pro
package.
package. The friendly license model keeps non-production evaluation token-free.
</p>
<Link className={styles.cardLink} to={docsRoutes.proUpgrade}>
Open the upgrade guide
</Link>
</article>
<article className={styles.migrationCard}>
<h3>3. Get a production license</h3>
<p>
Development, test, CI/CD, and staging can run without a token. Production deployments
require a paid license.
</p>
<Link className={styles.cardLink} href="https://pro.reactonrails.com/">
Pro pricing and sign up
</Link>
</article>
</div>
</div>
</section>
Expand Down
20 changes: 20 additions & 0 deletions prototypes/docusaurus/src/pages/pro.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@
flex-wrap: wrap;
}

.licenseHighlight {
max-width: 48rem;
margin-top: 1rem;
padding: 0.85rem 0.95rem;
border: 1px solid rgba(9, 105, 218, 0.3);
border-left: 4px solid var(--ifm-color-primary);
border-radius: 8px;
background: var(--site-surface);
}

.licenseHighlight strong {
display: block;
margin-bottom: 0.25rem;
color: var(--ifm-color-primary-dark);
}

.licenseHighlight span {
color: var(--ifm-color-content);
}

.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
Expand Down
35 changes: 24 additions & 11 deletions prototypes/docusaurus/src/pages/pro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,16 @@ export default function ProPage(): ReactNode {
<h1>React on Rails Pro</h1>
<p>
Pro extends React on Rails for teams that need higher SSR throughput, RSC-oriented
rendering features, and guided production support. You can evaluate Pro without a
license.
rendering features, and guided production support. The friendly license model lets
you evaluate Pro without a token before you need a production license.
</p>
<div className={styles.licenseHighlight}>
<strong>Friendly license model</strong>
<span>
No token is required for development, test, CI/CD, or staging. Production
deployments require a paid license.
</span>
</div>
<div className={styles.actions}>
<Link className="button button--primary button--lg" to={docsRoutes.proUpgrade}>
Review the upgrade guide
Expand All @@ -78,8 +85,8 @@ export default function ProPage(): ReactNode {
</Link>
<Link
className="button button--secondary button--lg"
href="https://www.shakacode.com/react-on-rails-pro/">
Contact ShakaCode
href="https://pro.reactonrails.com/">
Pro pricing / sign up
</Link>
</div>
</div>
Expand All @@ -104,18 +111,23 @@ export default function ProPage(): ReactNode {
</article>

<article className={styles.policyCard}>
<p className={styles.cardEyebrow}>Friendly evaluation policy</p>
<h2>Evaluate first, sort licensing second.</h2>
<p>You can try React on Rails Pro without a license while evaluating.</p>
<p className={styles.cardEyebrow}>Friendly license model</p>
<h2>Evaluate without a token.</h2>
<p>
Try Pro freely in development, test, CI/CD, and staging. If no license is
configured, Pro keeps running in unlicensed mode and logs license status instead of
blocking your app.
</p>
<p>
Production deployments require a paid license. Visit{' '}
<a href="https://pro.reactonrails.com/">Pro pricing and sign up</a> for current
options.
</p>
<p>
If your organization is budget-constrained, email{' '}
<a href="mailto:justin@shakacode.com">justin@shakacode.com</a>. We can grant free
licenses in qualifying cases.
</p>
<p className={styles.note}>
The goal is to make the upgrade path clear and low-friction, not to force a second
docs silo.
</p>
</article>
</div>
</section>
Expand Down Expand Up @@ -144,6 +156,7 @@ export default function ProPage(): ReactNode {
</div>
<p className={styles.note}>
Need pricing, implementation guidance, or a free-license discussion? Visit{' '}
<a href="https://pro.reactonrails.com/">Pro pricing and sign up</a> or{' '}
<a href="/docs/pro">the Pro docs landing page</a>.
</p>
</section>
Expand Down
3 changes: 0 additions & 3 deletions scripts/audit-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ function findSuspiciousLinks(lineInfo) {
if (target.includes("www.shakacode.com/react-on-rails-pro/docs/")) {
issues.push(`Legacy Pro docs domain link (${target}).`);
}
if (target.includes("pro.reactonrails.com")) {
issues.push(`Dead pro subdomain link (${target}).`);
}
}

return [...new Set(issues)];
Expand Down
44 changes: 26 additions & 18 deletions scripts/prepare-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ async function archiveLegacyDocs(docsRoot) {
return true;
}

export function fixProNodeRendererMdx(content) {
return content.replace("Direct render: <50ms", "Direct render: &lt;50ms");
}

async function fixKnownDocsIssues(docsRoot) {
await rewriteDocsByPattern(docsRoot, [
{
Expand Down Expand Up @@ -358,6 +362,8 @@ async function fixKnownDocsIssues(docsRoot) {
content.replace("using React 18's `renderToPipeableStream`", "using React 19's `renderToPipeableStream`")
);

await rewriteDoc(docsRoot, "pro/node-renderer.md", fixProNodeRendererMdx);

await rewriteDoc(docsRoot, "api-reference/view-helpers-api.md", (content) =>
content.replace("using React 18+ streaming", "using React 19+ streaming")
);
Expand Down Expand Up @@ -394,14 +400,10 @@ async function fixKnownDocsIssues(docsRoot) {
pattern: /https:\/\/www\.shakacode\.com\/react-on-rails-pro\/docs\//g,
replacement: "https://reactonrails.com/docs/pro/"
},
{
pattern: /https:\/\/pro\.reactonrails\.com\/?/g,
replacement: "https://reactonrails.com/docs/pro/"
}
]);
}

async function rewriteProLinks(proDocsRoot) {
export async function rewriteProLinks(proDocsRoot) {
if (!(await exists(proDocsRoot))) {
return;
}
Expand All @@ -414,15 +416,14 @@ async function rewriteProLinks(proDocsRoot) {
const updated = original
.replace(/((?:\.\.\/)+)oss\//g, "$1")
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails\/docs\//g, "https://reactonrails.com/docs/")
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails-pro\/docs\//g, "https://reactonrails.com/docs/pro/")
.replace(/https:\/\/pro\.reactonrails\.com\/?/g, "https://reactonrails.com/docs/pro/");
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails-pro\/docs\//g, "https://reactonrails.com/docs/pro/");
if (updated !== original) {
await fs.writeFile(absoluteFile, updated, "utf8");
}
});
}

async function rewriteFlattenedOssLinks(docsRoot) {
export async function rewriteFlattenedOssLinks(docsRoot) {
await walkFiles(docsRoot, async (absoluteFile, relativeFile) => {
if (!relativeFile.endsWith(".md") && !relativeFile.endsWith(".mdx")) {
return;
Expand All @@ -436,15 +437,14 @@ async function rewriteFlattenedOssLinks(docsRoot) {
.replace(/\.\.\/\.\.\/images\//g, "../images/")
.replace(/\.\.\/\.\.\/\.\.\/assets\//g, "../../assets/")
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails\/docs\//g, "https://reactonrails.com/docs/")
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails-pro\/docs\//g, "https://reactonrails.com/docs/pro/")
.replace(/https:\/\/pro\.reactonrails\.com\/?/g, "https://reactonrails.com/docs/pro/");
.replace(/https:\/\/www\.shakacode\.com\/react-on-rails-pro\/docs\//g, "https://reactonrails.com/docs/pro/");
if (updated !== original) {
await fs.writeFile(absoluteFile, updated, "utf8");
}
});
}

async function injectProFriendlyNotice(docsRoot) {
export async function injectProFriendlyNotice(docsRoot) {
const proIntroPath = path.join(docsRoot, "pro", "react-on-rails-pro.md");
if (!(await exists(proIntroPath))) {
return;
Expand All @@ -464,8 +464,8 @@ async function injectProFriendlyNotice(docsRoot) {
}
}

if (!updated.includes("Friendly evaluation policy")) {
const notice = `> **Friendly evaluation policy**\n> You can evaluate React on Rails Pro without a license.\n> If your organization is budget-constrained, email [justin@shakacode.com](mailto:justin@shakacode.com). We can provide free licenses in qualifying cases.\n\n`;
if (!/Friendly license model/i.test(updated)) {
const notice = `> **Friendly license model**\n> Try React on Rails Pro freely in development, test, CI/CD, and staging. No token is required to evaluate. If no license is configured, Pro keeps running in unlicensed mode and logs license status instead of blocking your app. Production deployments require a paid license; see [Pro pricing and sign up](https://pro.reactonrails.com/).\n\n`;
updated = updated.replace(/^# React on Rails Pro\s*\n+/m, `# React on Rails Pro\n\n${notice}`);
}

Expand Down Expand Up @@ -652,14 +652,20 @@ async function normalizeCodeFences(docsRoot) {
}
}

function docsHomeMarkdown(sourceMarkdown, { hasArchive }) {
export function docsHomeMarkdown(sourceMarkdown, { hasArchive }) {
const archiveBlock = hasArchive ? "- [Historical Reference](./archive/README.md)\n" : "";
const friendlyLicenseSection = `## Friendly License Model

- Try React on Rails Pro freely in development, test, CI/CD, and staging. No token is required to evaluate.
- Production deployments require a paid license. See [Pro pricing and sign up](https://pro.reactonrails.com/) for current options. If your organization is budget-constrained, [contact us](mailto:justin@shakacode.com) about free or low-cost licenses.
`;

const updated = sourceMarkdown
.trim()
.replaceAll("(./oss/", "(./")
.replace("](https://reactonrails.com/examples)", "](/examples)")
.replace(/\n- \[Documentation website\]\(https:\/\/reactonrails\.com\/docs\/\)\s*/g, "\n")
.replace(/## Friendly evaluation policy\n\n[\s\S]*?(?=\n## )/, `${friendlyLicenseSection}\n`)
.replace("## Need more help?\n\n", `## Need more help?\n\n${archiveBlock}`);

return `---\ncustom_edit_url: null\n---\n\n${updated}\n`;
Expand Down Expand Up @@ -778,7 +784,9 @@ async function main() {
await prepareDocusaurus();
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
if (process.argv[1] && path.resolve(process.argv[1]) === __filename) {
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
}
Loading
Loading