Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
"@heroicons/react": "^2.0.18",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.5",
"@storybook/react-vite": "^8.0.8",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
24 changes: 24 additions & 0 deletions src/components/Avatar/Avatar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@


/**
* @typedef {Object} AvatarProps
* @property {string} AvatarProps.imgSrc - some description here
* @property {string} AvatarProps.descricao - some description here
* @property { 'square' | 'circle' } AvatarProps.format - Formato do Avatar (Circular ou Quadrado)
* @param {AvatarProps} props
* @param props
*/


export function Avatar({ imgSrc, descricao, format }) {

return (
<div className="container flex justify-center items-center">
<img
src={imgSrc}
className={`avatar ${format === 'square' ? 'square' : 'rounded-full'} w-32 h-32 border-3 border-white object-cover`}
alt={descricao}
/>
</div>
);
}
48 changes: 48 additions & 0 deletions src/components/Avatar/Avatar.stories.tsx

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions src/components/Popup/PopUp.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Button } from "@/components/ui/button";
import { useToast } from "@/components/ui/use-toast";
import { Toaster } from "@/components/ui/toaster";
import { CheckCircledIcon } from '@radix-ui/react-icons';

/**
* @typedef {Object} ToastContentProps
* @property {string} mensagem - A mensagem a ser exibida no toast.
*/

/**
* Componente para o conteúdo do Toast
* @param {ToastContentProps} props
*/
export const ToastContent = ({ mensagem }) => (
<div className="flex items-center">
<CheckCircledIcon className="mr-2 text-green-500" width="24" height="24" />
<span>{mensagem}</span>
</div>
);

/**
* @typedef {Object} PopUpProps
* @property {string} [buttonText="Save"] - O texto do botão.
* @property {string} [mensagem="Cat was updated"] - A mensagem do toast.
*/

/**
* Componente PopUp
* @param {PopUpProps} props
*/

export function PopUp({ buttonText = "Save", mensagem = "Cat was updated" }) {
const { toast } = useToast();

const handleSaveClick = () => {
toast({
description: <ToastContent mensagem={mensagem} />,
});
};

return (
<Button variant="outline" onClick={handleSaveClick}>
{buttonText}
</Button>
);
}

// Componente PopUpWithToaster (wrapper para PopUp e Toaster)
export const PopUpWithToaster = ({ buttonText = "Save", mensagem = "Cat was updated" }) => (
<>
<PopUp buttonText={buttonText} mensagem={mensagem} />
<Toaster />
</>
);
31 changes: 31 additions & 0 deletions src/components/Popup/PopUp.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Meta, StoryObj } from '@storybook/react';
import { PopUp, PopUpWithToaster } from './PopUp';


const meta: Meta<typeof PopUp> = {
title: 'Components/PopUp', // Define um título para o grupo de stories
component: PopUp,
argTypes: {
buttonText: { control: 'text' },
mensagem: { control: 'text' },
},
};

export default meta;
type Story = StoryObj<typeof PopUp>;

// Stories
export const Primary: Story = {
render: () => <PopUpWithToaster />,
}; // Usa os valores padrão das props

export const Secondary: Story = {
args: {
buttonText: "Atualizar",
mensagem: "As informações do gato foram atualizadas com sucesso!",
},
render: ( {buttonText, mensagem}) => <PopUpWithToaster
buttonText={ buttonText }
mensagem={ mensagem }
/>,
};
127 changes: 127 additions & 0 deletions src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const ToastProvider = ToastPrimitives.Provider

const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName

const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)

const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
)
})
Toast.displayName = ToastPrimitives.Root.displayName

const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
))
ToastAction.displayName = ToastPrimitives.Action.displayName

const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName

const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
{...props}
/>
))
ToastTitle.displayName = ToastPrimitives.Title.displayName

const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
))
ToastDescription.displayName = ToastPrimitives.Description.displayName

type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>

type ToastActionElement = React.ReactElement<typeof ToastAction>

export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
}
33 changes: 33 additions & 0 deletions src/components/ui/toaster.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast"
import { useToast } from "@/components/ui/use-toast"

export function Toaster() {
const { toasts } = useToast()

return (
<ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
)
})}
<ToastViewport />
</ToastProvider>
)
}
Loading