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
13 changes: 6 additions & 7 deletions _TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@ https://aws.plainenglish.io/how-to-build-a-chatbot-using-aws-lex-and-lambda-in-2
- Moving the scroll bar up quickly with the mouse seems to make the header logic break - the Switcher component and Breadcrumbs are hidden under the header
- Themepicker and search icon are too big in non-squished header. Logo too - the initial presentation should be smaller.

## Content Issues
## Resume

- Need an article on OpenStack
- Finish styling

## Youtube video for Backstage IDP hero on Home page
## Env Vars

- Discuss agentic AI integrations to add to Backstage
- Home page reorganization: move the "What I Deliver" box from the Hero into the Backstage image. Move the Backstage image / video to the hero.
- Add HubSpot env vars to Vercel

## Deep Dive Link
## Content Issues

- Add a "Preview Special" item to our Download CTA that lets the user know the Deep Dive content can be previewed in HTML format, and offer a switch to it.
- Need an article on OpenStack
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
105 changes: 86 additions & 19 deletions scripts/generate-pdfs/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const CONTENT_PADDING_LEFT_IN = CONTENT_PADDING_CM.left / CM_PER_IN
const CONTENT_PADDING_RIGHT_IN = CONTENT_PADDING_CM.right / CM_PER_IN
const CONTENT_HEIGHT_PX = (PAGE_HEIGHT_IN - CONTENT_PADDING_TOP_IN - CONTENT_PADDING_BOTTOM_IN) * 96
const CONTENT_WIDTH_PX = (8.5 - CONTENT_PADDING_LEFT_IN - CONTENT_PADDING_RIGHT_IN) * 96
const ASSET_SETTLE_TIMEOUT_MS = 30_000
const LAYOUT_SETTLE_DELAY_MS = 500

// --- Templates ---

Expand Down Expand Up @@ -116,6 +118,81 @@ const writeMergedPdf = async ({ coverPdfBytes, fullPdfBytes, outputPdf }) => {
writeFileSync(outputPdf, await mergedPdf.save())
}

const wait = (durationMs) => new Promise(resolve => setTimeout(resolve, durationMs))

const forceLazyAssetsToLoad = async (page) => {
await page.evaluate(async () => {
const documentRoot = globalThis.document.scrollingElement ?? globalThis.document.documentElement
const pause = (durationMs) => new Promise(resolve => globalThis.setTimeout(resolve, durationMs))
const viewportHeight = globalThis.innerHeight || 800
const step = Math.max(200, Math.floor(viewportHeight * 0.9))

for (const image of Array.from(globalThis.document.images)) {
image.loading = 'eager'
image.decoding = 'sync'

if ('fetchPriority' in image) {
image.fetchPriority = 'high'
}
}

for (let top = 0; top < documentRoot.scrollHeight; top += step) {
documentRoot.scrollTop = top
await pause(50)
}

documentRoot.scrollTop = 0
await pause(50)
})
}

const waitForPageAssets = async (page) => {
await page.evaluate(async (timeoutMs) => {
const pause = (durationMs) => new Promise(resolve => globalThis.setTimeout(resolve, durationMs))
const withTimeout = async (promiseFactory) => {
const timeoutPromise = pause(timeoutMs)

try {
await Promise.race([promiseFactory(), timeoutPromise])
} catch {
await timeoutPromise
}
}

if (globalThis.document.fonts?.ready) {
await withTimeout(() => globalThis.document.fonts.ready)
}

await Promise.allSettled(
Array.from(globalThis.document.images).map(async (image) => {
image.loading = 'eager'
image.decoding = 'sync'

if ('fetchPriority' in image) {
image.fetchPriority = 'high'
}

if (!image.complete) {
await withTimeout(() => new Promise(resolve => {
const done = () => {
image.removeEventListener('load', done)
image.removeEventListener('error', done)
resolve()
}

image.addEventListener('load', done, { once: true })
image.addEventListener('error', done, { once: true })
}))
}

if (typeof image.decode === 'function') {
await withTimeout(() => image.decode())
}
})
)
}, ASSET_SETTLE_TIMEOUT_MS)
}

// --- PDF generation ---

const generatePdf = async (browser, slug) => {
Expand All @@ -135,24 +212,14 @@ const generatePdf = async (browser, slug) => {
height: Math.round(CONTENT_HEIGHT_PX),
})

await page.goto(inputUrl, { waitUntil: 'networkidle2', timeout: 60_000 })
await page.goto(inputUrl, { waitUntil: 'domcontentloaded', timeout: 60_000 })
await page.emulateMediaType('print')

// Wait for web fonts so PDF typography matches the site instead of fallback metrics.
await page.evaluate(() => {
return globalThis.document.fonts.ready
})
await forceLazyAssetsToLoad(page)
await waitForPageAssets(page)

// Wait for all images to finish loading
await page.evaluate(() => {
const doc = globalThis.document

return Promise.all(
Array.from(doc.images)
.filter(img => !img.complete)
.map(img => new Promise(r => { img.onload = r; img.onerror = r }))
)
})
// Final settle — give any remaining layout shifts a moment to resolve
await wait(LAYOUT_SETTLE_DELAY_MS)

const title = await page.title()

Expand Down Expand Up @@ -184,10 +251,10 @@ const generatePdf = async (browser, slug) => {
}
}, CONTENT_HEIGHT_PX)

const [coverPdfBytes, fullPdfBytes] = await Promise.all([
page.pdf(buildPdfOptions({ includeHeaderFooter: false, pageRanges: '1' })),
page.pdf(buildPdfOptions({ includeHeaderFooter: true, title })),
])
const coverPdfBytes = await page.pdf(
buildPdfOptions({ includeHeaderFooter: false, pageRanges: '1' })
)
const fullPdfBytes = await page.pdf(buildPdfOptions({ includeHeaderFooter: true, title }))

await writeMergedPdf({ coverPdfBytes, fullPdfBytes, outputPdf })

Expand Down
9 changes: 5 additions & 4 deletions scripts/generate-pdfs/styles.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export const buildTemplateStyles = () => {

.pdf-layout-footer__company-name {
color: #001A39;
font-size: 12pt;
font-size: 10pt;
font-style: normal;
font-weight: 600;
line-height: 1.1;
Expand All @@ -193,7 +193,7 @@ export const buildTemplateStyles = () => {

.pdf-layout-footer__address p {
color: #001A39;
font-size: 10pt;
font-size: 8pt;
font-style: normal;
line-height: 1.1;
margin: 0;
Expand All @@ -207,7 +207,7 @@ export const buildTemplateStyles = () => {
display: flex;
justify-content: center;
color: #001A39;
font-size: 10pt;
font-size: 8pt;
line-height: 1.1;
margin: 0;
width: 20%;
Expand All @@ -221,14 +221,15 @@ export const buildTemplateStyles = () => {
align-items: flex-end;
display: flex;
flex-direction: column;
gap: 2px;
justify-content: center;
min-width: 0;
width: 40%;
}

.pdf-layout-footer__right p {
color: #001A39;
font-size: 10pt;
font-size: 8pt;
font-style: normal;
line-height: 1.2;
margin: 0;
Expand Down
Binary file removed src/Why Your Quality Gates Are Slowing You Down.pdf
Binary file not shown.
84 changes: 84 additions & 0 deletions src/components/FileExplorer/Print.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
import type { FileSystemNode } from '@components/FileExplorer/client/index'
import PrintNode from '@components/FileExplorer/PrintNode.astro'

export type Props = {
data: FileSystemNode[]
figure?: string
classes?: {
wrapper?: string
}
fullWidth?: boolean
}

const {
data = [],
figure,
classes = {},
fullWidth = true,
} = Astro.props

const wrapperClass = [
'file-explorer-print',
'my-6',
'block',
'mx-auto',
fullWidth ? 'w-full' : 'w-fit max-w-full',
classes.wrapper,
].filter(Boolean).join(' ')
---

<figure class={wrapperClass}>
<div class="file-explorer-print__panel mx-auto max-w-full rounded-lg bg-(--color-page-base) p-6 font-mono text-left">
<ul class="list-none p-0 m-0 tree-root" aria-label={figure ? undefined : 'File explorer'}>
{data.map((node, index) => <PrintNode node={node} path={`${index}`} isRoot />)}
</ul>
</div>

{figure && <figcaption class="mx-auto mt-3 max-w-full text-center italic" set:html={figure} />}
</figure>

<style>
.file-explorer-print {
margin-inline: auto;
}

.file-explorer-print__panel {
font-size: var(--font-size-base);
line-height: 1.6;
margin-inline: auto;
max-width: 100%;
overflow-wrap: anywhere;
width: fit-content;
}

.file-explorer-print :global(.node) {
white-space: normal;
}

.file-explorer-print :global(.node-name),
.file-explorer-print :global(.comment),
.file-explorer-print :global(.note-text) {
font-size: inherit;
}

.file-explorer-print figcaption {
font-size: var(--font-size-base);
}

@media print {
.file-explorer-print {
break-inside: auto;
}

.file-explorer-print__panel {
break-inside: auto;
overflow: visible;
}

.file-explorer-print :global(.children),
.file-explorer-print :global(li) {
break-inside: auto;
}
}
</style>
74 changes: 74 additions & 0 deletions src/components/FileExplorer/PrintNode.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
import type { FileSystemNode } from '@components/FileExplorer/client/index'
import FileExplorerPrintNode from '@components/FileExplorer/PrintNode.astro'

export interface Props {
node: FileSystemNode
path: string
isRoot?: boolean
}

const { node } = Astro.props
const { path, isRoot = false } = Astro.props
const hasChildren = node.type === 'folder' && (node.children?.length ?? 0) > 0
const isFolder = node.type === 'folder'
const liClasses = isRoot
? 'relative'
: "relative before:content-[''] before:absolute before:top-[0.8rem] before:-left-6 before:w-5 before:border-t before:border-dashed before:border-(--color-trim) last:border-l last:border-solid last:border-(--color-page-base) last:-ml-6 last:pl-6 last:before:left-0"
---

<li class={liClasses}>
<div class="flex items-center">
<div class="group flex items-center py-1 node">
{hasChildren && (
<span
aria-hidden="true"
class="mr-2 inline-flex w-4 shrink-0 items-center justify-center text-(--color-trim)"
>
<svg
aria-hidden="true"
focusable="false"
class="h-4 w-4 fill-none stroke-current rotate-90"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M7 5l6 5-6 5" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
</svg>
</span>
)}

{isFolder ? (
<span aria-hidden="true" class="mr-2 inline-flex items-center text-secondary node-icon folder-icon">
<svg aria-hidden="true" focusable="false" class="h-6 w-6 fill-current icon-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
</svg>
</span>
) : (
<span aria-hidden="true" class="mr-2 inline-flex items-center text-(--color-content-offset) node-icon file-icon">
<svg aria-hidden="true" focusable="false" class="h-6 w-6 fill-current icon-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z" />
</svg>
</span>
)}

<span class={`text-(--color-content) node-name ${isFolder ? 'font-medium' : 'font-normal file-name'}`}>
{node.name}
</span>
{node.comment && <span class="ml-6 text-(--color-content-offset) italic comment"># {node.comment}</span>}
</div>

{node.note && (
<span class="ml-3 inline-flex items-center rounded-full border border-trim bg-page-base px-2 py-0.5 text-xs font-semibold leading-none text-secondary">
i
</span>
)}
</div>

{node.note && <p class="ml-9 mt-2 note-text leading-relaxed text-content-offset">{node.note}</p>}

{hasChildren && (
<ul class="list-none p-0 m-0 pl-6 border-l border-dashed border-(--color-trim) ml-2 children">
{node.children?.map((childNode, index) => <FileExplorerPrintNode node={childNode} path={`${path}/${index}`} />)}
</ul>
)}
</li>
4 changes: 3 additions & 1 deletion src/pages/print/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Callout from '@components/Callout/index.astro'
import CodeTabs from '@components/Code/CodeTabs/index.astro'
import Copy from '@components/Copy/index.astro'
import Diagram from '@components/Diagram/index.astro'
import FileExplorer from '@components/FileExplorer/Print.astro'
import Icon from '@components/Icon/index.astro'
import Inset from '@components/Inset/index.astro'
import List from '@components/List/index.astro'
Expand All @@ -33,6 +34,7 @@ const PdfComponents = {
Callout,
Copy,
Diagram,
FileExplorer,
Icon,
Image,
Inset,
Expand Down Expand Up @@ -72,7 +74,7 @@ const publishDate = article.data.publishDate
---

<PrintLayout pageTitle={article.data.title}>
<div class="print-document">
<div class="print-document print-document--font-size-px">
{/* Cover page */}
<Cover article={article} />

Expand Down
Loading
Loading