Skip to content
Merged
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
10 changes: 5 additions & 5 deletions apps/docs/content/alpine/how-to/build-pipeline.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ zerops:
# OPTIONAL. Customize the build environment by installing additional packages
# or tools to the base build environment.
prepareCommands:
- apk add --no-cache something
- sudo apk add --no-cache something
- curl something else

# OPTIONAL. Build your application
Expand Down Expand Up @@ -52,7 +52,7 @@ zerops:
# OPTIONAL. Customize the runtime Alpine environment by installing additional
# dependencies to the base Alpine runtime environment.
prepareCommands:
- apk add --no-cache something
- sudo apk add --no-cache something
- curl something else

# OPTIONAL. Run one or more commands each time a new runtime container
Expand Down Expand Up @@ -172,7 +172,7 @@ zerops:
# OPTIONAL. Customize the build environment by installing additional packages
# or tools to the base build environment.
prepareCommands:
- apk add --no-cache something
- sudo apk add --no-cache something
- curl something else
...
```
Expand Down Expand Up @@ -515,7 +515,7 @@ zerops:
# OPTIONAL. Customise the runtime environment by installing additional packages
# or tools to the base Alpine runtime environment.
prepareCommands:
- apk add --no-cache something
- sudo apk add --no-cache something
- curl something else
...
```
Expand Down Expand Up @@ -569,7 +569,7 @@ zerops:
# OPTIONAL. Customise the runtime environment by installing additional packages
# or tools to the base Alpine runtime environment.
prepareCommands:
- apk add --no-cache something
- sudo apk add --no-cache something
- curl something else
...
```
Expand Down
8 changes: 4 additions & 4 deletions apps/docs/content/alpine/how-to/customize-runtime.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import { SetVar, Var, VarLink, VarCodeBlock, VarReasons } from '@site/src/compon
run:
base: {{serviceVersion}}
prepareCommands:
- apk update
- apk add --no-cache imagemagick ffmpeg`} />
- sudo apk update
- sudo apk add --no-cache imagemagick ffmpeg`} />
<SetVar name="buildFilesCode" value={
`...
build:
Expand All @@ -34,8 +34,8 @@ import { SetVar, Var, VarLink, VarCodeBlock, VarReasons } from '@site/src/compon
run:
...
prepareCommands:
- apk update
- apk add --no-cache libpq-dev py3-pip
- sudo apk update
- sudo apk add --no-cache libpq-dev py3-pip
- pip install -r requirements.txt`} />

## Build Custom Runtime Images
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/content/features/pipeline.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Build & deploy pipeline
description: Learn how to setup a build & deploy pipeline at Zerops.
description: Learn how to set up a build & deploy pipeline at Zerops.
---

import GroupCards from '../../src/components/GroupCards';
Expand Down Expand Up @@ -222,7 +222,7 @@ When your application requires additional system packages, libraries, or tools i
### When to use custom runtime images

Build custom runtime images when you need:
- System packages or libraries for runtime operations (e.g., `apk add imagemagick` for image processing)
- System packages or libraries for runtime operations (e.g., `sudo apk add imagemagick` for image processing)
- Library dependencies for interpreted languages or dynamically linked binaries
- System-level tools or utilities your application requires
- Customized base operating system or additional software layers
Expand Down
10 changes: 5 additions & 5 deletions apps/docs/content/python/how-to/build-pipeline.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ zerops:
# OPTIONAL. Customize the build environment by installing additional packages
# or tools to the base build environment.
prepareCommands:
- apt install python3-pip # already installed for Python services
- sudo apt install python3-pip # already installed for Python services
...
```

Expand All @@ -229,8 +229,8 @@ Use following syntax to run all commands in the same environment context. For ex
```yaml
prepareCommands:
- |
apt update
apt install python3-pip # already installed for Python services
sudo apt update
sudo apt install python3-pip # already installed for Python services
```

#### Run prepare commands as a separate shell instances
Expand All @@ -239,8 +239,8 @@ When the following syntax is used, each command is triggered in a separate envir

```yaml
prepareCommands:
- apt update
- apt install python3-pip # already installed for Python services
- sudo apt update
- sudo apt install python3-pip # already installed for Python services
```

### deployFiles
Expand Down
83 changes: 83 additions & 0 deletions apps/docs/src/components/CopyPageMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState } from "react"
import { useLocation } from "@docusaurus/router"

export function CopyPageMenu() {
const [copyFeedback, setCopyFeedback] = useState(false)
const location = useLocation()

const mdPath = `${location.pathname}.md`

async function handleCopyMarkdown() {
try {
const response = await fetch(mdPath)
if (!response.ok) throw new Error("Failed to fetch")
const text = await response.text()
await navigator.clipboard.writeText(text)
setCopyFeedback(true)
setTimeout(() => setCopyFeedback(false), 2000)
} catch {
console.error("Failed to copy markdown")
}
}

function handleViewMarkdown() {
window.open(mdPath, "_blank", "noopener,noreferrer")
}

return (
<div className="copy-page-menu">
<div className="copy-page-menu__divider" />
<button
onClick={handleCopyMarkdown}
className="copy-page-menu__item"
type="button"
>
<svg
width="14"
height="14"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.333 5.333V3.467c0-.747 0-1.12.146-1.406a1.333 1.333 0 0 1 .583-.582c.285-.146.659-.146 1.405-.146h5.066c.747 0 1.12 0 1.406.146.25.128.454.332.582.582.146.286.146.66.146 1.406v5.066c0 .747 0 1.12-.146 1.406a1.333 1.333 0 0 1-.582.583c-.286.145-.66.145-1.406.145h-1.866M3.467 14.667h5.066c.747 0 1.12 0 1.406-.146.25-.128.454-.332.582-.583.146-.285.146-.659.146-1.405V7.467c0-.747 0-1.12-.146-1.406a1.333 1.333 0 0 0-.582-.583c-.286-.145-.66-.145-1.406-.145H3.467c-.747 0-1.12 0-1.406.145a1.333 1.333 0 0 0-.582.583C1.333 6.347 1.333 6.72 1.333 7.467v5.066c0 .746 0 1.12.146 1.405.128.251.332.455.582.583.286.146.66.146 1.406.146Z"
stroke="currentColor"
strokeWidth="1.2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
{copyFeedback ? "Copied!" : "Copy as Markdown"}
</button>
<button
onClick={handleViewMarkdown}
className="copy-page-menu__item"
type="button"
>
<svg
width="14"
height="14"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.333 8s2.667-5.333 6.667-5.333S14.667 8 14.667 8s-2.667 5.333-6.667 5.333S1.333 8 1.333 8Z"
stroke="currentColor"
strokeWidth="1.2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"
stroke="currentColor"
strokeWidth="1.2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
View as Markdown
</button>
</div>
)
}
27 changes: 27 additions & 0 deletions apps/docs/src/css/components/copy-page-menu.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.copy-page-menu {
@apply mt-1.5;
}

.copy-page-menu__divider {
@apply h-[1px] w-[50%] bg-medusa-border-base mb-0.75 mx-auto;
}

.copy-page-menu__item {
@apply flex items-center gap-[6px];
@apply py-[6px] px-1 rounded-md cursor-pointer text-left;
@apply bg-transparent border-0;
@apply text-compact-x-small-plus whitespace-nowrap;
@apply text-gray-700 dark:text-gray-300;
@apply hover:text-gray-900 dark:hover:text-gray-100;
@apply hover:bg-medusa-bg-base-hover;
@apply active:bg-medusa-bg-base-pressed;
@apply transition-colors duration-200;
}

.copy-page-menu__item + .copy-page-menu__item {
@apply mt-[2px];
}

.copy-page-menu__item svg {
@apply flex-shrink-0;
}
3 changes: 1 addition & 2 deletions apps/docs/src/css/components/toc.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
@apply before:bg-toc dark:before:bg-toc-dark;
@apply before:bg-no-repeat before:bg-[length:14px_10px] before:bg-[center_left];
@apply before:pl-[22px] before:content-['On_this_page'] before:pb-0 text-compact-small-plus;
@apply after:content-[''] after:absolute after:left-0 after:top-2.5;
@apply after:h-full after:w-[1px] after:bg-medusa-border-base;
}

.theme-doc-toc-desktop .table-of-contents .table-of-contents__link {
Expand All @@ -25,6 +23,7 @@

.theme-doc-toc-desktop .table-of-contents__link {
@apply relative text-compact-x-small-plus;
@apply text-medusa-fg-muted;
@apply hover:text-medusa-fg-base;
}

Expand Down
1 change: 1 addition & 0 deletions apps/docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,5 @@ html[data-theme='dark'] .docsearch-btn:hover {
@import url('./_docusaurus.css');
@import url('./components/sidebar.css');
@import url('./components/toc.css');
@import url('./components/copy-page-menu.css');
@import url('./components/tooltip.css');
116 changes: 83 additions & 33 deletions apps/docs/src/plugins/markdown-source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,34 +291,77 @@ function cleanMarkdownForDisplay(content, filepath, siteDir, docsDir) {
// 6. Substitute variables like {data.something}
content = substituteVariables(content, siteDir);

// 7. Convert HTML images to markdown
// 7a. Convert <Image> React components to markdown (before removing figure tags)
content = content.replace(
/<Image\s+[^>]*(?:lightImage|src)=["']([^"']+)["'][^>]*alt=["']([^"']+)["'][^>]*\/?>/g,
(match, src, alt) => {
return `![${alt}](${src})`;
// 6b. Resolve Var components (SetVar, Var, VarLink, VarCodeBlock, VarReasons, IfVar)
// First, collect all SetVar values
const vars = {};
content.replace(
/<SetVar\s+name=["']([^"']+)["']\s+value=["']([^"']+)["']\s*\/>/g,
(match, name, value) => { vars[name] = value; return ''; }
);
// Also collect SetVar with JSX expression values (simple strings)
content.replace(
/<SetVar\s+name=["']([^"']+)["']\s+value=\{([^}]+)\}\s*\/>/g,
(match, name, expr) => {
// Only handle simple string/data references, skip arrays/objects
const trimmed = expr.trim();
if (!trimmed.startsWith('[') && !trimmed.startsWith('{')) {
// Try to resolve data.x.y references
const dataMatch = trimmed.match(/^data\.(.+)$/);
if (dataMatch) {
const data = getDataJson(siteDir);
const keys = dataMatch[1].split('.');
let val = data;
for (const key of keys) {
if (val && typeof val === 'object' && key in val) {
val = val[key];
} else {
val = null;
break;
}
}
if (val !== null && typeof val !== 'object') {
vars[name] = String(val);
}
}
}
return '';
}
);

// 7b. Convert standard HTML <img> tags to markdown
// Remove all SetVar tags
content = content.replace(/<SetVar\s+[^>]*\/>/g, '');
// Replace <Var name="x" /> with the variable value
content = content.replace(
/<img\s+[^>]*src=["']([^"']+)["'][^>]*alt=["']([^"']*?)["'][^>]*\/?>/g,
(match, src, alt) => {
return `![${alt || 'image'}](${src})`;
}
/<Var\s+name=["']([^"']+)["']\s*\/>/g,
(match, name) => vars[name] || ''
);

// 7c. Convert HTML images with require() syntax
// Replace <VarLink name="x" path="/{{VAR}}/...">children</VarLink> with markdown links
content = content.replace(
/<p align="center">\s*\n?\s*<img src=\{require\(['"]([^'"]+)['"]\)\.default\} alt="([^"]*)"(?:\s+width="[^"]*")?\s*\/>\s*\n?\s*<\/p>/g,
(match, imagePath, alt) => {
const cleanPath = imagePath.replace('@site/static/', '/');
return `![${alt}](${cleanPath})`;
/<VarLink\s+name=["']([^"']+)["']\s+path=["']([^"']+)["']\s*>([\s\S]*?)<\/VarLink>/g,
(match, name, path, children) => {
const value = vars[name] || '';
const href = path.replace(/\{\{VAR\}\}/g, value);
// Clean children of any remaining HTML/JSX
const cleanChildren = children
.replace(/<Var\s+name=["']([^"']+)["']\s*\/>/g, (m, n) => vars[n] || '')
.replace(/<code>(.*?)<\/code>/g, '`$1`')
.replace(/<[^>]+>/g, '')
.trim();
return `[${cleanChildren}](${href})`;
}
);
// Remove VarCodeBlock, VarReasons, IfVar (complex components we can't easily resolve)
content = content.replace(/<VarCodeBlock\s+[^>]*\/>/g, '');
content = content.replace(/<VarReasons\s+[^>]*\/>/g, '');
content = content.replace(/<IfVar\s+[^>]*>([\s\S]*?)<\/IfVar>/g, '$1');

// 7. Remove all images (HTML and markdown) - sources won't resolve in raw markdown
content = content.replace(/<Image\s+[^>]*\/?>/g, '');
content = content.replace(/<img\s+[^>]*\/?>/g, '');
content = content.replace(/<p align="center">\s*\n?\s*<img[^>]*\/>\s*\n?\s*<\/p>/g, '');
content = content.replace(/!\[[^\]]*\]\([^)]+\)/g, '');

// 8. Remove figure tags but keep any text content inside
content = content.replace(/<figure[^>]*>([\s\S]*?)<\/figure>/g, '$1');
// 8. Remove figure tags
content = content.replace(/<figure[^>]*>([\s\S]*?)<\/figure>/g, '');

// 9. Convert YouTube iframes to text links
content = content.replace(
Expand All @@ -335,29 +378,36 @@ function cleanMarkdownForDisplay(content, filepath, siteDir, docsDir) {
// 11. Remove <Head> components
content = content.replace(/<Head>[\s\S]*?<\/Head>/g, '');

// 12. Convert FAQ components to readable markdown (preserve content)
// 12. Convert HTML <a> tags to markdown links
content = content.replace(
/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/g,
(match, href, text) => {
// Clean inner HTML tags (like <code>, <strong>) to plain text
const cleanText = text
.replace(/<code>(.*?)<\/code>/g, '`$1`')
.replace(/<strong>(.*?)<\/strong>/g, '**$1**')
.replace(/<em>(.*?)<\/em>/g, '*$1*')
.replace(/<b>(.*?)<\/b>/g, '**$1**')
.replace(/<[^>]+>/g, '')
.trim();
return `[${cleanText}](${href})`;
}
);

// 13. Convert FAQ components to readable markdown (preserve content)
content = convertFAQToMarkdown(content);

// 13. Convert Tabs/TabItem components to readable markdown (preserve content)
// 14. Convert Tabs/TabItem components to readable markdown (preserve content)
content = convertTabsToMarkdown(content);

// 14. Convert details/summary components to readable markdown (preserve content)
// 15. Convert details/summary components to readable markdown (preserve content)
content = convertDetailsToMarkdown(content);

// 15. Remove custom React/MDX components while preserving tables
// 16. Remove custom React/MDX components while preserving tables
content = preserveTablesWhileProcessing(content, (section) => {
return section.replace(/<[A-Z][a-zA-Z]*[\s\S]*?(?:\/>|<\/[A-Z][a-zA-Z]*>)/g, '');
});

// 16. Convert relative image paths to absolute paths
content = content.replace(
/!\[([^\]]*)\]\((\.\/)?img\/([^)]+)\)/g,
(match, alt, relPrefix, filename) => {
// Convert to absolute path: /docs/path/to/file/img/filename
return `![${alt}](/${fileDir}img/${filename})`;
}
);

// 17. Remove consecutive blank lines (keep max 2 newlines = 1 blank line)
const lines = content.split('\n');
const processedLines = [];
Expand Down
Loading