diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md new file mode 100644 index 0000000..9c5e264 --- /dev/null +++ b/packages/ui-avatar/CHANGELOG.md @@ -0,0 +1,16 @@ +# CHANGELOG - @halvaradop/ui-avatar + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Addedd + +### Fixed + +### Changed + +### Removed diff --git a/packages/ui-avatar/README.md b/packages/ui-avatar/README.md new file mode 100644 index 0000000..bb190c1 --- /dev/null +++ b/packages/ui-avatar/README.md @@ -0,0 +1,118 @@ +# @halvaradop/ui-avatar + +`@halvaradop/ui-avatar` is an accessible, reusable, and customizable `Avatar` component from the `@halvaradop/ui` React library. Built with React and styled using TailwindCSS v4, it provides pre-styled components to accelerate UI development. + +## Installation + +There are two versions available: one for React 19 (stable) and one for React 18 (legacy).. + +### React 19 (Stable) + +```bash +npm install @halvaradop/ui-avatar +yarn add @halvaradop/ui-avatar +pnpm add @halvaradop/ui-avatar +``` + +## Usage + +The `Avatar` component offers several additional props for customization. Import the `Avatar` component as shown below: + +```tsx +import { Avatar } from "@halvaradop/ui-avatar" + +export default function App() { + return +} +``` + +### Prop Reference + +This component is currently a avatar/placeholder and does not have implemented props yet. + +| Prop | Accepted Values | Default | Description | +| ---- | --------------- | ------- | ------------------------ | +| - | - | - | No props implemented yet | + +## Styling + +The component supports TailwindCSS v4. To customize colors, use the following CSS variables. For the full theme, see [the theme file](https://github.com/halvaradop/ui/blob/master/tailwind.css). + +```css +@import "tailwindcss"; + +@theme { + --breakpoint-base: 900px; + + --opacity-cursor: 80%; + + --color-muted: oklch(65% 0.01 260); + --color-border: oklch(70% 0.02 260); + --color-overlay: oklch(30% 0.02 260 / 0.3); + + --color-success: oklch(75% 0.18 140); + --color-danger: oklch(65% 0.2 25); + + --color-surface: oklch(98% 0 0); + --color-on-surface: oklch(20% 0.02 260); + + --color-primary: oklch(30% 0 270); + --color-on-primary: oklch(95% 0 0); + + --color-secondary: oklch(60% 0 270); + --color-on-secondary: oklch(10% 0 0); + + --color-ghost: oklch(94% 0.01 260); + + --color-disabled: oklch(92% 0 0); + --color-on-disabled: oklch(60% 0.01 260); +} +``` + +### Dark Theme Support + +The library currently supports only a dark theme. To enable it, update the CSS variables as follows: + +```css +:is(html, body).dark { + --opacity-cursor: 80%; + + --color-muted: oklch(70% 0.01 260); + --color-border: oklch(35% 0.01 260); + + --color-success: oklch(70% 0.19 150); + --color-danger: oklch(65% 0.22 25); + + --color-overlay: oklch(0% 0 0 / 0.6); + + --color-surface: oklch(15% 0.005 260); + --color-on-surface: oklch(95% 0.01 260); + + --color-primary: oklch(90% 0 0); + --color-on-primary: oklch(20% 0 270); + + --color-secondary: oklch(60% 0 0); + --color-on-secondary: oklch(10% 0 270); + + --color-ghost: oklch(25% 0 0); + --color-disabled: oklch(30% 0 0); +} +``` + +## About + +This component is part of the [`@halvaradop/ui`](https://github.com/halvaradop/ui) library, a collection of production-ready React components built with [TypeScript](https://www.typescriptlang.org/) and [React](https://react.dev/), and styled using [Tailwind CSS](https://tailwindcss.com/) and [Class Variance Authority (CVA)](https://cva.style/). Designed for modern web applications, it aims to deliver accessible, customizable, and maintainable UI building blocks to accelerate your development workflow. + +### License + +This project is licensed under the `MIT License`. For full details, see the [LICENSE](https://github.com/halvaradop/ui/blob/master/LICENSE) file. + +### Contributing + +We welcome and appreciate contributions to the `@halvaradop/ui` library! + +To get started, please read our [Contributing Guide](https://github.com/halvaradop/ui/blob/master/docs/CONTRIBUTING.md). All contributors are expected to follow our [Code of Conduct](https://github.com/halvaradop/.github/blob/master/.github/CODE_OF_CONDUCT.md). + +--- + +Made with ❤️ by the `@halvaradop/ui` team. diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json new file mode 100644 index 0000000..edc856c --- /dev/null +++ b/packages/ui-avatar/package.json @@ -0,0 +1,73 @@ +{ + "name": "@halvaradop/ui-avatar", + "version": "1.0.0", + "private": false, + "description": "A customizable Avatar component for @halvaradop/ui library with Tailwind CSS styling.", + "type": "module", + "scripts": { + "dev": "tsup --watch", + "build": "tsup && pnpm clean:cts", + "build:release": "tsup --env.NODE_ENV=production && pnpm clean:cts", + "format": "prettier --write . --cache --cache-location .cache/.prettiercache", + "format:check": "prettier --check .", + "lint": "eslint . --cache --cache-location .cache/.eslintcache", + "lint:fix": "eslint . --fix --cache --cache-location .cache/.eslintcache", + "clean": "pnpm clean:dist && pnpm clean:modules && pnpm clean:turbo", + "clean:dist": "rm -rf dist", + "clean:modules": "rm -rf node_modules", + "clean:turbo": "rm -rf .turbo", + "clean:cts": "rm -rf ./dist/*.cts", + "check-types": "tsc --noEmit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/halvaradop/ui.git" + }, + "keywords": [ + "react", + "component", + "tailwindcss", + "react", + "ui", + "ui library" + ], + "author": "Hernan Alvarado ", + "license": "MIT", + "bugs": { + "url": "https://github.com/halvaradop/ui/issues" + }, + "homepage": "https://github.com/halvaradop/ui#readme", + "files": [ + "dist" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./avatar": { + "types": "./dist/avatar.d.ts", + "import": "./dist/avatar.js", + "require": "./dist/avatar.cjs" + }, + "./avatar-group": { + "types": "./dist/avatar-group.d.ts", + "import": "./dist/avatar-group.js", + "require": "./dist/avatar-group.cjs" + } + }, + "dependencies": { + "@halvaradop/ui-core": "workspace:*", + "@halvaradop/ui-slot": "workspace:*", + "class-variance-authority": "catalog:" + }, + "devDependencies": { + "@ui/ts-config": "workspace:*", + "@ui/tsup-config": "workspace:*" + }, + "peerDependencies": { + "react": "catalog:", + "react-dom": "catalog:" + } +} diff --git a/packages/ui-avatar/src/avatar-group.tsx b/packages/ui-avatar/src/avatar-group.tsx new file mode 100644 index 0000000..4dda183 --- /dev/null +++ b/packages/ui-avatar/src/avatar-group.tsx @@ -0,0 +1,26 @@ +import { merge, type PropsWithChildren } from "@halvaradop/ui-core" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot, type SlotProps } from "@halvaradop/ui-slot" + +export type AvatarGroupProps = VariantProps & PropsWithChildren> & {} + +export const avatarGroupVariants = cva("text-on-surface", { + variants: { + variant: { + rounded: "rounded-full", + square: "rounded-[calc(var(---rounded-sm)*0.5)]", + }, + size: { + sm: "size-sm space-x-sm", + base: "size-base space-x-base", + md: "size-md space-x-md", + lg: "size-lg space-x-lg", + }, + }, +}) + +export const AvatarGroup = ({ className, variant, size, children, asChild, ...props }: AvatarGroupProps) => { + const SlotComponent = asChild ? Slot : "figure" + + return {children} +} diff --git a/packages/ui-avatar/src/avatar.stories.tsx b/packages/ui-avatar/src/avatar.stories.tsx new file mode 100644 index 0000000..6ec6a5d --- /dev/null +++ b/packages/ui-avatar/src/avatar.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { Avatar } from "./avatar.js" +import { DecoratorWrapper } from "@/ui/ui-utils/src/decorator.js" +import { DocsPage } from "@/ui/ui-utils/src/docs-page.js" + +const meta: Meta = { + title: "ui-avatar", + tags: ["autodocs"], + component: Avatar, + args: {}, + argTypes: {}, + parameters: { + layout: "centered", + backgrounds: { + default: "light", + grid: true, + }, + docs: { + page: () => , + }, + }, + decorators: [DecoratorWrapper], +} satisfies Meta + +type Story = StoryObj + +export const Base: Story = { + parameters: { + skipDecorator: true, + }, +} + +export const Variants: Story = {} + +export default meta diff --git a/packages/ui-avatar/src/avatar.tsx b/packages/ui-avatar/src/avatar.tsx new file mode 100644 index 0000000..cd1b058 --- /dev/null +++ b/packages/ui-avatar/src/avatar.tsx @@ -0,0 +1,26 @@ +import { merge, type ComponentProps } from "@halvaradop/ui-core" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot, type SlotProps } from "@halvaradop/ui-slot" + +export type AvatarProps = VariantProps & SlotProps<"figure"> & {} + +export const avatarVariants = cva("text-on-surface", { + variants: { + variant: { + rounded: "rounded-full", + square: "rounded-[calc(var(---rounded-sm)*0.5)]", + }, + size: { + sm: "size-sm", + base: "size-base", + md: "size-md", + lg: "size-lg", + } + }, +}) + +export const Avatar = ({ className, variant, children, asChild, ...props }: AvatarProps) => { + const SlotComponent = asChild ? Slot : "figure" + + return +} diff --git a/packages/ui-avatar/src/index.tsx b/packages/ui-avatar/src/index.tsx new file mode 100644 index 0000000..13ffb3c --- /dev/null +++ b/packages/ui-avatar/src/index.tsx @@ -0,0 +1,2 @@ +export * from "./avatar.js" +export * from "./avatar-group.js" diff --git a/packages/ui-avatar/tsconfig.json b/packages/ui-avatar/tsconfig.json new file mode 100644 index 0000000..0296bda --- /dev/null +++ b/packages/ui-avatar/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@ui/ts-config/tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/ui-avatar/tsup.config.ts b/packages/ui-avatar/tsup.config.ts new file mode 100644 index 0000000..76baf3a --- /dev/null +++ b/packages/ui-avatar/tsup.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "tsup" +import { tsupConfig } from "@ui/tsup-config" + +export default defineConfig((options) => { + const env = options.env?.NODE_ENV + return { + ...tsupConfig, + sourcemap: env !== "production", + minify: env === "production", + bundle: env === "production", + ...options, + } +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8cd692..666f2e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,6 +185,31 @@ importers: specifier: workspace:* version: link:../ts-config + packages/ui-avatar: + dependencies: + '@halvaradop/ui-core': + specifier: workspace:* + version: link:../ui-core + '@halvaradop/ui-slot': + specifier: workspace:* + version: link:../ui-slot + class-variance-authority: + specifier: 'catalog:' + version: 0.7.0 + react: + specifier: 'catalog:' + version: 19.1.1 + react-dom: + specifier: 'catalog:' + version: 19.1.1(react@19.1.1) + devDependencies: + '@ui/ts-config': + specifier: workspace:* + version: link:../../configs/ts-config + '@ui/tsup-config': + specifier: workspace:* + version: link:../../configs/tsup-config + packages/ui-button: dependencies: '@halvaradop/ui-core':