Kosmesis
Components

Web Preview

A link-preview card for a web page an AI response references. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add web-preview
pnpm dlx kosmesis add web-preview
yarn dlx kosmesis add web-preview
bunx kosmesis add web-preview

Copy and paste the following code into your project.

web-preview.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { cn } from "@/lib/utils";export interface WebPreviewProps {  url: string;  title: string;  description?: string;  image?: string;  class?: string;}@Component()export class WebPreview extends StatelessComponent<WebPreviewProps> {  render() {    const { url, title, description, image, class: cls } = this.props;    let hostname = url;    try {      hostname = new URL(url).hostname;    } catch {      // not a fully-qualified URL — fall back to showing it as-is    }    return (      <a        href={url}        target="_blank"        rel="noopener noreferrer"        data-slot="web-preview"        class={cn("flex gap-3 rounded-lg border bg-card p-3 text-card-foreground hover:bg-accent/50", cls)}      >        {image && <img src={image} alt="" class="size-14 shrink-0 rounded-md object-cover" />}        <div class="min-w-0 flex-1">          <p class="truncate text-sm font-medium">{title}</p>          {description && <p class="mt-0.5 line-clamp-2 text-xs text-muted-foreground">{description}</p>}          <p class="mt-1 truncate text-xs text-muted-foreground">{hostname}</p>        </div>      </a>    );  }}

Install the following dependencies:

npm install @praxisjs/css
pnpm add @praxisjs/css
yarn add @praxisjs/css
bun add @praxisjs/css

Copy and paste the following code into your project.

web-preview.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class WebPreviewStyles extends Stylesheet {  $root = this.css({    display: "flex",    gap: "0.75rem",    borderRadius: "0.5rem",    border: `1px solid ${t.border}`,    backgroundColor: t.card,    color: t.cardForeground,    padding: "0.75rem",  }).on("&:hover", { backgroundColor: `color-mix(in oklab, ${t.accent} 50%, transparent)` });  $image = this.css({ height: "3.5rem", width: "3.5rem", flexShrink: 0, borderRadius: "0.375rem", objectFit: "cover" });  $body = this.css({ minWidth: 0, flex: "1 1 0%" });  $title = this.css({ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontSize: "0.875rem", fontWeight: 500 });  $description = this.css({    marginTop: "0.125rem",    display: "-webkit-box",    WebkitLineClamp: "2",    WebkitBoxOrient: "vertical",    overflow: "hidden",    fontSize: "0.75rem",    color: t.mutedForeground,  });  $host = this.css({    marginTop: "0.25rem",    overflow: "hidden",    textOverflow: "ellipsis",    whiteSpace: "nowrap",    fontSize: "0.75rem",    color: t.mutedForeground,  });}export interface WebPreviewProps {  url: string;  title: string;  description?: string;  image?: string;  class?: string;}@Component()export class WebPreview extends StatelessComponent<WebPreviewProps> {  @Styled(WebPreviewStyles) $s!: WebPreviewStyles;  render() {    const { url, title, description, image, class: cls } = this.props;    let hostname = url;    try {      hostname = new URL(url).hostname;    } catch {      // not a fully-qualified URL — fall back to showing it as-is    }    return (      <a href={url} target="_blank" rel="noopener noreferrer" data-slot="web-preview" class={cx(this.$s.$root, cls)}>        {image && <img src={image} alt="" class={this.$s.$image} />}        <div class={this.$s.$body}>          <p class={this.$s.$title}>{title}</p>          {description && <p class={this.$s.$description}>{description}</p>}          <p class={this.$s.$host}>{hostname}</p>        </div>      </a>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. The hostname is derived from url via the URL constructor (falling back to the raw string if it isn't fully-qualified). image is optional — without it, the card is just title/description/hostname.

Usage

import { WebPreview } from "@/components/ui/web-preview";

<WebPreview
  url="https://example.com/docs"
  title="Example Docs"
  description="Everything you need to get started."
/>

Props

PropTypeDefault
urlstring
titlestring
descriptionstring
imagestring
classstring

On this page