npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@algenium/blocks

v1.0.1

Published

Shared UI components for Algenium applications

Readme

@algenium/blocks

Shared UI components for Algenium applications

A collection of reusable, accessible UI components built with React, Radix UI, and Tailwind CSS. Designed for use across all Algenium applications.

Installation

npm install @algenium/blocks
# or
pnpm add @algenium/blocks

Peer Dependencies

This package requires the following peer dependencies:

pnpm add react react-dom next-themes lucide-react motion

Configuration

Tailwind CSS

Configure your Tailwind CSS to include this package:

// tailwind.config.js
module.exports = {
	content: [
		// ... your other content paths
		"./node_modules/@algenium/blocks/dist/**/*.js",
	],
	// ... rest of your config
};

Components

ThemeSwitcher

A theme switcher component that integrates with next-themes. Supports light, dark, and system themes.

Features:

  • Multiple variants (default, mini)
  • Multiple sizes (sm, md, lg)
  • Multiple shapes (rounded, pill)
  • Internationalization support

Usage:

import { ThemeSwitcher } from "@algenium/blocks";

// Default usage
<ThemeSwitcher />;

// With custom labels (for i18n)
<ThemeSwitcher
	labels={{
		theme: "Theme",
		system: "System",
		light: "Light",
		dark: "Dark",
	}}
/>;

// Mini variant (icon only with dropdown)
<ThemeSwitcher variant="mini" />;

// Different sizes and shapes
<ThemeSwitcher size="sm" shape="pill" />;

Props:

interface ThemeSwitcherProps {
	variant?: "default" | "mini";
	size?: "sm" | "md" | "lg";
	shape?: "rounded" | "pill";
	showIcon?: boolean;
	labels?: ThemeSwitcherLabels;
	className?: string;
}

LanguageSwitcher

A language switcher component with support for multiple languages and display variants.

Features:

  • Multiple variants (default, mini)
  • Multiple sizes (sm, md, lg)
  • Dropdown positioning control
  • Language flag/icon support
  • Internationalization support

Usage:

import { LanguageSwitcher } from "@algenium/blocks";

const languages = [
	{ key: "en", label: "EN", nativeName: "English" },
	{ key: "es", label: "ES", nativeName: "Español" },
];

<LanguageSwitcher
	languages={languages}
	currentLanguage="en"
	onLanguageChange={(key) => setLanguage(key)}
	labels={{ language: "Language" }}
/>;

// Mini variant
<LanguageSwitcher
	variant="mini"
	languages={languages}
	currentLanguage="en"
	onLanguageChange={(key) => setLanguage(key)}
/>;

// With icon
<LanguageSwitcher
	languages={languages}
	currentLanguage="en"
	onLanguageChange={(key) => setLanguage(key)}
	showIcon
/>;

Props:

interface LanguageSwitcherProps {
	languages: Language[];
	currentLanguage: string;
	onLanguageChange: (languageKey: string) => void;
	variant?: "default" | "mini";
	size?: "sm" | "md" | "lg";
	dropdownAlign?: "start" | "center" | "end";
	showIcon?: boolean;
	labels?: LanguageSwitcherLabels;
	className?: string;
}

interface Language {
	key: string;
	label: string;
	nativeName: string;
}

AvatarEditor

An interactive avatar editor with zoom, rotation, and drag controls.

Features:

  • Image zoom via UI buttons and slider (0.5x - 3x)
  • Image rotation in 15° increments (0° - 360°)
  • Drag to reposition image
  • Real-time preview with circular crop
  • Customizable editor size
  • Optional grid overlay for alignment
  • Reset all transforms
  • Touch-optimized controls for mobile

Usage:

import { AvatarEditor } from "@algenium/blocks";

<AvatarEditor
	value={avatarData}
	onChange={(editedImage) => {
		console.log("Edited image:", editedImage);
	}}
/>;

// With custom size and grid
<AvatarEditor
	value={avatarData}
	onChange={setAvatarData}
	size={280}
	showGrid={true}
/>;

// With custom output settings
<AvatarEditor
	value={avatarData}
	onChange={setAvatarData}
	outputSize={512}
	outputFormat="jpeg"
	outputQuality={0.95}
/>;

// With large controls for mobile/touch
<AvatarEditor
	value={avatarData}
	onChange={setAvatarData}
	controlSize="large"
/>;

Props:

interface AvatarEditorProps {
	value?: string | null;
	onChange?: (dataUrl: string | null) => void;
	size?: number;
	showGrid?: boolean;
	outputSize?: number;
	outputFormat?: "png" | "jpeg" | "webp";
	outputQuality?: number;
	controlSize?: "default" | "large";
	className?: string;
}

AvatarEditorDialog

A complete avatar editing experience with preview display and edit dialog.

Features:

  • Large avatar display with edit button
  • Opens fullscreen drawer on mobile, modal on desktop
  • Integrated AvatarEditor with all controls
  • Controlled component (value/onChange)
  • Optional async save handler with feedback
  • Success/error feedback messages
  • Customizable sizes and labels
  • Accessibility optimized

Usage:

import { AvatarEditorDialog } from "@algenium/blocks";

// Basic usage with value/onChange
<AvatarEditorDialog value={avatar} onChange={setAvatar} />;

// With async save handler
<AvatarEditorDialog
	value={avatar}
	onChange={setAvatar}
	onSave={async (dataUrl) => {
		const result = await uploadAvatar(dataUrl);
		return result.success;
	}}
	dialogTitle="Edit Profile Picture"
	acceptText="Save"
	cancelText="Cancel"
	successMessage="Avatar saved successfully!"
	errorMessage="Failed to save avatar"
/>;

// With custom sizes
<AvatarEditorDialog
	value={avatar}
	onChange={setAvatar}
	displaySize={120}
	editorSize={280}
	outputSize={512}
/>;

Props:

interface AvatarEditorDialogProps {
	value?: string | null;
	onChange?: (dataUrl: string | null) => void;
	onSave?: (dataUrl: string) => Promise<boolean> | boolean;
	displaySize?: number;
	editorSize?: number;
	outputSize?: number;
	placeholder?: string;
	editLabel?: string;
	dialogTitle?: string;
	acceptText?: string;
	cancelText?: string;
	successMessage?: string;
	errorMessage?: string;
	className?: string;
}

NotificationsWidget

A compact notification bell widget with popover display, sound alerts, and animations.

Features:

  • Bell icon with unread count badge
  • Popover with scrollable notification list
  • Multiple notification types (info, success, warning, error)
  • Sound notifications (chime, bell, pop, ding)
  • Pulse animations (ring, glow, bounce)
  • Mark as read/dismiss actions
  • Click-to-navigate support
  • Customizable colors, sizes, and sounds

Usage:

import { NotificationsWidget, Notification } from "@algenium/blocks";

const notifications: Notification[] = [
	{
		id: "1",
		title: "New message",
		message: "You have a new message from John",
		type: "info",
		timestamp: new Date(),
		read: false,
	},
	{
		id: "2",
		title: "Task completed",
		message: "Your export task finished successfully",
		type: "success",
		timestamp: new Date(Date.now() - 1000 * 60 * 5),
		read: false,
	},
];

<NotificationsWidget
	notifications={notifications}
	onMarkAsRead={(id) => markAsRead(id)}
	onMarkAllAsRead={() => markAllAsRead()}
	onDismiss={(id) => dismiss(id)}
	onClearAll={() => clearAll()}
	onNotificationClick={(notification) => {
		if (notification.href) {
			router.push(notification.href);
		}
	}}
	playSound
	soundType="chime"
	size="md"
	dotColor="red"
	pulseStyle="ring"
/>;

// Minimal usage
<NotificationsWidget
	notifications={notifications}
	onMarkAsRead={(id) => markAsRead(id)}
/>;

// Custom configuration
<NotificationsWidget
	notifications={notifications}
	onMarkAsRead={(id) => markAsRead(id)}
	size="lg"
	dotColor="primary"
	soundType="bell"
	pulseStyle="glow"
	maxVisible={10}
	title="Alerts"
	emptyMessage="No alerts"
/>;

Props:

interface NotificationsWidgetProps {
	notifications: Notification[];
	onMarkAsRead?: (id: string) => void;
	onMarkAllAsRead?: () => void;
	onDismiss?: (id: string) => void;
	onClearAll?: () => void;
	onNotificationClick?: (notification: Notification) => void;
	size?: "sm" | "md" | "lg";
	maxVisible?: number; // Default: 5
	playSound?: boolean; // Default: true
	soundUrl?: string; // Custom sound file URL
	soundType?: "chime" | "bell" | "pop" | "ding" | "none"; // Default: "chime"
	soundCooldown?: number; // Default: 2000ms
	className?: string;
	emptyMessage?: string; // Default: "No notifications"
	title?: string; // Default: "Notifications"
	dotColor?: "red" | "blue" | "green" | "amber" | "purple" | "primary"; // Default: "red"
	showPulse?: boolean; // Default: true
	pulseStyle?: "ring" | "glow" | "bounce" | "none"; // Default: "ring"
}

interface Notification {
	id: string;
	title: string;
	message?: string;
	type?: "info" | "success" | "warning" | "error"; // Default: "info"
	timestamp: Date;
	read?: boolean;
	href?: string; // Optional link for click navigation
}

UI Primitives

The package also exports underlying UI primitives that can be used independently:

Button

import { Button } from "@algenium/blocks";

<Button variant="default">Click me</Button>;
<Button variant="outline" size="sm">
	Small
</Button>;
<Button variant="ghost" size="icon">
	<Icon />
</Button>;

Dialog

import {
	Dialog,
	DialogTrigger,
	DialogContent,
	DialogHeader,
	DialogTitle,
	DialogDescription,
	DialogFooter,
} from "@algenium/blocks";

<Dialog>
	<DialogTrigger>Open</DialogTrigger>
	<DialogContent>
		<DialogHeader>
			<DialogTitle>Title</DialogTitle>
			<DialogDescription>Description</DialogDescription>
		</DialogHeader>
		{/* Content */}
		<DialogFooter>{/* Actions */}</DialogFooter>
	</DialogContent>
</Dialog>;

Drawer

import {
	Drawer,
	DrawerTrigger,
	DrawerContent,
	DrawerHeader,
	DrawerTitle,
} from "@algenium/blocks";

<Drawer>
	<DrawerTrigger>Open</DrawerTrigger>
	<DrawerContent>
		<DrawerHeader>
			<DrawerTitle>Title</DrawerTitle>
		</DrawerHeader>
		{/* Content */}
	</DrawerContent>
</Drawer>;

DropdownMenu

import {
	DropdownMenu,
	DropdownMenuTrigger,
	DropdownMenuContent,
	DropdownMenuItem,
} from "@algenium/blocks";

<DropdownMenu>
	<DropdownMenuTrigger>Open</DropdownMenuTrigger>
	<DropdownMenuContent>
		<DropdownMenuItem>Item 1</DropdownMenuItem>
		<DropdownMenuItem>Item 2</DropdownMenuItem>
	</DropdownMenuContent>
</DropdownMenu>;

Popover

import { Popover, PopoverTrigger, PopoverContent } from "@algenium/blocks";

<Popover>
	<PopoverTrigger>Open</PopoverTrigger>
	<PopoverContent>Content here</PopoverContent>
</Popover>;

ScrollArea

import { ScrollArea } from "@algenium/blocks";

<ScrollArea className="h-[200px]">{/* Scrollable content */}</ScrollArea>;

Slider

import { Slider } from "@algenium/blocks";

<Slider
	value={[50]}
	onValueChange={(value) => setValue(value[0])}
	max={100}
	step={1}
/>;

Toggle

import { Toggle } from "@algenium/blocks";

<Toggle pressed={isPressed} onPressedChange={setIsPressed}>
	Toggle me
</Toggle>;

Tooltip

import {
	Tooltip,
	TooltipTrigger,
	TooltipContent,
	TooltipProvider,
} from "@algenium/blocks";

<TooltipProvider>
	<Tooltip>
		<TooltipTrigger>Hover me</TooltipTrigger>
		<TooltipContent>Tooltip text</TooltipContent>
	</Tooltip>
</TooltipProvider>;

Utilities

cn (Class Name utility)

A utility function for conditionally merging Tailwind CSS classes.

import { cn } from "@algenium/blocks";

const className = cn("base-class", condition && "conditional-class", {
	"another-class": someCondition,
});

TypeScript Support

All components are fully typed with TypeScript. Import types as needed:

import type {
	ThemeSwitcherProps,
	LanguageSwitcherProps,
	Language,
	AvatarEditorProps,
	AvatarEditorDialogProps,
	NotificationsWidgetProps,
	Notification,
	NotificationType,
} from "@algenium/blocks";

Best Practices

Internationalization

All text-based components accept label props for i18n:

import { useTranslation } from "your-i18n-library";

const { t } = useTranslation();

<ThemeSwitcher
	labels={{
		theme: t("theme"),
		light: t("light"),
		dark: t("dark"),
		system: t("system"),
	}}
/>;

Theme Integration

Components use CSS variables for theming. Ensure your app provides these variables:

:root {
	--background: 0 0% 100%;
	--foreground: 222.2 84% 4.9%;
	--primary: 222.2 47.4% 11.2%;
	--muted: 210 40% 96.1%;
	--border: 214.3 31.8% 91.4%;
	/* ... other variables */
}

Notification Management

For NotificationsWidget, implement a notification management system:

// Example notification manager
const [notifications, setNotifications] = useState<Notification[]>([]);

const markAsRead = (id: string) => {
	setNotifications((prev) =>
		prev.map((n) => (n.id === id ? { ...n, read: true } : n)),
	);
};

const dismiss = (id: string) => {
	setNotifications((prev) => prev.filter((n) => n.id !== id));
};

const addNotification = (notification: Omit<Notification, "id">) => {
	const id = crypto.randomUUID();
	setNotifications((prev) => [{ ...notification, id }, ...prev]);
};

Contributing

This package is maintained as part of the Algenium monorepo. See the main repository for contribution guidelines.

License

Proprietary - Algenium © 2026

Version

Current version: 1.0.0-rc.4

Support

For issues or questions, contact the Algenium development team or open an issue in the repository.