TODAY I LEARNED
by lubosmato
by lubosmato
PostgreSQL ships with createdb — a CLI wrapper around CREATE DATABASE. No need to open a psql session or remember the SQL syntax. It uses your system user by default, same as psql.
PayloadCMS stores rich text in Lexical format, but the search plugin needs plaintext for indexing. The @payloadcms/richtext-lexical package exports a convertLexicalToPlaintext utility that handles this conversion.
Use it in the beforeSync hook of the search plugin to transform rich text fields before they're indexed.
When using custom CSS variables in React inline styles, TypeScript complains because CSSProperties doesn't know about custom properties.
Use TypeScript module augmentation to extend React's CSSProperties interface:
Mastra's RequestContext lets you customize agent behavior on a per-request basis. By extending the base class with your own type parameters, you get type-safe access to context values like user sessions or feature flags. This is more flexible than creating separate agents - you maintain one agent definition while dynamically adjusting its capabilities based on who’s calling it and what they’re allowed to do.
The satisfies keyword is perfect here because it validates the object shape against Record<BlockSlug, ComponentType<any>> without widening the type. This means TypeScript will error at compile time if you add a new block type in Payload but forget to add the corresponding component. Unlike a type annotation (: Record<...>), satisfies preserves the narrow literal types of the keys, giving you autocomplete and strict key checking while still enforcing the constraint.
React doesn't recognize custom element tag names in JSX, so TypeScript complains. You can fix this by extending React's IntrinsicElements with your component's props alongside DetailedHTMLProps to keep standard React props like children, className, ref, and key working.
You can automatically pick black or white color based on a background color using a only CSS.
The trick abuses relative color syntax in oklch. It extracts the perceptual lightness (l) of the background, subtracts it from a threshold (0.6), and multiplies by infinity. The result is either +infinity (clamped to white) or -infinity (clamped to black). Zero chroma and hue ensure a pure achromatic result.
Perfect for dynamic badges, tags, or any element where the background color is unpredictable. Works in all modern browsers today.
No JS needed for parallax anymore. The animation-timeline: scroll() property lets you drive a CSS animation by scroll position instead of time. Define a regular @keyframes animation with translate3d, set animation-timeline: scroll(root), and each layer moves at its own speed based on a CSS custom property. Stack multiple layers with different --parallax-y values and you've got depth.
Did you know asciinema supports real-time terminal streaming? Running asciinema stream -r starts a live stream of your terminal session, giving anyone with the link a real-time view of what you're doing. Perfect for remote pair programming with Neovim or live demos.
I use Neovim BTW!
psql can accept a full connection URI instead of passing individual flags for host, port, database, and user.
This is especially handy when working with managed database providers (Supabase, Neon, Railway, etc.) since they typically give you a connection string you can copy and paste directly. No more juggling five different flags.
createdb my_nice_db
# instead of:
# psql -c "CREATE DATABASE my_nice_db;"❯ asciinema stream -r
::: asciinema session started
::: Live streaming at https://asciinema.org/s/BAgxaJcQbsr55T
::: Press <ctrl+d> or type 'exit' to endfc -p # commands you run after this won't be saved to your shell history (for current session only)
psql postgres://myuser:mypassword@localhost:5432/mydb
# same as:
psql -h localhost -p 5432 -U myuser -d mydb
fc -P # back to normalimport { searchPlugin } from "@payloadcms/plugin-search"
import { convertLexicalToPlaintext } from "@payloadcms/richtext-lexical/plaintext"
export const search = searchPlugin({
collections: ["posts"],
beforeSync: async ({ originalDoc, searchDoc }) => {
return {
...searchDoc,
// Convert Lexical JSON to searchable plaintext
description: convertLexicalToPlaintext({
data: originalDoc.description, // Lexical rich text field
}),
}
},
})import { RequestContext as _RequestContext } from "@mastra/core/request-context";
import { Agent } from "@mastra/core/agent"
class RequestContext extends _RequestContext<{
enableCmsTools?: boolean;
}> {}
// In agent config:
export const agent = new Agent({
id: "my-agent",
name: "My Agent",
// ...
tools: ({ requestContext }) => {
const context = requestContext as RequestContext;
const tools = {
searchWebpages,
fetchPage,
// Conditionally add CMS tools:
...(context.get("enableCmsTools")
? {
createPage,
updatePage,
}
: {}),
}
return tools;
},
});
function Component() {
return (
<div
style={{
"--parallax-y": "-420px", // OK
"--other-var": "42px", // Error
}}
/>
)
}
declare module "react" {
interface CSSProperties {
[`--parallax-y`]?: `${number}px`
}
}
import type { Page } from "@/payload-types"
import type { BlockSlug } from "payload"
import type { ComponentType } from "react"
export function RenderBlocks({ blocks }: { blocks: Page["content"][0][] }) {
return blocks.map((block, index) => {
if (!(block.blockType in blockComponents)) {
return null
}
const Block = blockComponents[block.blockType]
return (
<div key={index}>
{/* @ts-expect-error block props should be correct at this point */}
<Block {...block} />
</div>
)
})
}
const blockComponents = {
pageTitle: PageTitleBlock,
sectionHeader: SectionHeaderBlock,
anchorNavigation: AnchorNavigationBlock,
textImage: TextImageBlock,
productCardGrid: ProductCardGridBlock,
topicTeaser: TopicTeaserBlock,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} satisfies Record<BlockSlug, ComponentType<any>>import { useRef, type DetailedHTMLProps, type HTMLAttributes } from "react"
declare module "react/jsx-runtime" {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace JSX {
interface IntrinsicElements {
"my-button": DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> & {
/** The variant of the button, either "primary" or "secondary". */
variant: "primary" | "secondary"
/** Whether the button is disabled. @default false */
disabled?: boolean
}
}
}
}
export function Page() {
const btnRef = useRef<HTMLButtonElement>(null)
return (
<my-button variant="primary" key="some-key" ref={btnRef}>
Submit
</my-button>
)
}<Badge
style={{
backgroundColor: tag.color,
color: `oklch(from ${tag.color} calc((0.6 - l) * infinity) 0 0)`,
}}
>
{tag.name}
</Badge>
@keyframes parallax {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, var(--parallax-y), 0);
}
}
.scene {
position: relative;
}
.parallax-layer {
--parallax-y: -20vh;
position: absolute;
inset: 0;
animation: parallax linear both;
animation-timeline: scroll(root);
}
/* Different speeds per layer via custom property */
.bg-layer { --parallax-y: -5vh; }
.fg-layer { --parallax-y: -10vh; }
/* Usage:
<div class="scene">
<div class="parallax-layer bg-layer"></div>
<div class="parallax-layer fg-layer"></div>
<div class="content">Your content here</div>
</div>
*/