chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { useState } from 'react';
import { Prose } from '#/components/molecules/prose.jsx';
import { cn } from '#/lib/utils.js';
/**
* A field for words that will be read as markdown, with the reading beside
* the writing.
*
* What is typed here is rendered wherever it is read, so a writer who cannot
* see that finds out after publishing. The preview is the same renderer the
* page uses, so a fenced block that reads wrong here reads wrong there.
*
* Preview is a tab rather than a second pane, because at this width two
* columns would give each of them half a line of code.
*/
export function MarkdownField({
value,
onChange,
placeholder,
rows = 8,
disabled,
label,
autoFocus,
className,
}) {
const [preview, setPreview] = useState(false);
return (
<div className={cn('flex flex-col', className)}>
<div className="flex items-center gap-1 border-border border-b">
{[
{ key: 'write', label: 'Write' },
{ key: 'preview', label: 'Preview' },
].map((tab) => {
const current = (tab.key === 'preview') === preview;
return (
<button
key={tab.key}
type="button"
onClick={() => setPreview(tab.key === 'preview')}
className={cn(
'-mb-px cursor-pointer border-b-2 px-3 py-2 text-[13px]',
current
? 'border-key text-foreground'
: 'border-transparent text-faint hover:text-muted-foreground',
)}
>
{tab.label}
</button>
);
})}
</div>
{preview ? (
// The written height, so the field does not jump as a reader looks.
<div
className="overflow-y-auto px-3 py-2.5"
style={{ minHeight: `${rows * 1.6 + 1.25}rem` }}
>
{value.trim() ? (
<Prose text={value} className="max-w-3xl" />
) : (
<p className="text-[12.5px] text-faint">Nothing to preview yet.</p>
)}
</div>
) : (
<textarea
value={value}
onChange={(event) => onChange(event.target.value)}
placeholder={placeholder}
aria-label={label}
rows={rows}
disabled={disabled}
// biome-ignore lint/a11y/noAutofocus: a page opened to write one thing
autoFocus={autoFocus}
className="w-full resize-y border-0 bg-transparent px-3 py-2.5 font-mono text-[13px] text-foreground placeholder:text-faint focus:outline-none"
/>
)}
</div>
);
}