---
import Base from '../layouts/Base.astro';
import { getPaste } from '../lib/r2';
const { id } = Astro.params;
if (!id) {
return Astro.redirect('/');
}
const runtime = Astro.locals.runtime as { env: { BUCKET: import('@cloudflare/workers-types').R2Bucket } };
const bucket = runtime?.env?.BUCKET;
if (!bucket) {
return new Response('Storage not configured', { status: 500 });
}
const paste = await getPaste(bucket, id);
if (!paste) {
return new Response('Paste not found', { status: 404 });
}
const { metadata } = paste;
let textContent = '';
let imageDataUrl = '';
// Convert stored OKLCH values back to CSS, with fallback for legacy hex values
const storedColor = metadata.bgColor;
let bgColor = 'oklch(98% 0.01 90)';
if (storedColor) {
if (storedColor.startsWith('#')) {
// Legacy hex color - use as-is for backwards compatibility
bgColor = storedColor;
} else {
// OKLCH stored format: "L C H"
const [L, C, h] = storedColor.split(' ');
bgColor = `oklch(${L}% ${C} ${h})`;
}
}
// Generate OG image URL
const siteUrl = Astro.url.origin;
const ogImage = metadata.type === 'image'
? `${siteUrl}/raw/${id}`
: `${siteUrl}/og/${id}.svg`;
// Generate description for text pastes
let description = 'Shared via Ansible';
if (metadata.type === 'text' && paste.body) {
const reader = paste.body.getReader();
const decoder = new TextDecoder();
let result = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
result += decoder.decode(value, { stream: true });
}
result += decoder.decode();
textContent = result;
// Set description to first 150 chars of text
description = textContent.slice(0, 150).replace(/\n/g, ' ');
if (textContent.length > 150) description += '...';
} else if (metadata.type === 'image' && paste.body) {
const reader = paste.body.getReader();
const chunks: Uint8Array[] = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
const combined = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
combined.set(chunk, offset);
offset += chunk.length;
}
// Convert to base64
let binary = '';
for (let i = 0; i < combined.length; i++) {
binary += String.fromCharCode(combined[i]);
}
const base64 = btoa(binary);
imageDataUrl = `data:${metadata.contentType};base64,${base64}`;
}
---
<Base title="Ansible" description={description} ogImage={ogImage} ogType="article">
<header class="header">
<a href="/" class="title">Ansible: Quickly share temporary text or images</a>
<button id="copy-btn">Copy Link</button>
</header>
<div class="content-box" style={`background: ${bgColor};`}>
{metadata.type === 'text' ? (
<pre>{textContent}</pre>
) : (
<img src={imageDataUrl} alt="Shared image" class="paste-image" />
)}
</div>
</Base>
<script>
const copyBtn = document.getElementById('copy-btn') as HTMLButtonElement;
copyBtn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(window.location.href);
copyBtn.textContent = 'Copied!';
setTimeout(() => {
copyBtn.textContent = 'Copy Link';
}, 2000);
} catch (error) {
console.error('Failed to copy:', error);
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = window.location.href;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
copyBtn.textContent = 'Copied!';
setTimeout(() => {
copyBtn.textContent = 'Copy Link';
}, 2000);
}
});
</script>