Skip to content

Commit

Permalink
feat: Add px helper function for pixel string conversion, enhance Swi…
Browse files Browse the repository at this point in the history
…tch component behavior, and update Card and BooleanCard styles
  • Loading branch information
PolGubau committed Oct 31, 2024
1 parent b94237a commit bd7bd51
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 107 deletions.
3 changes: 3 additions & 0 deletions packages/ui/debug.log
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
[1026/154037.906:ERROR:crashpad_client_win.cc(810)] not connected
[1031/084040.057:ERROR:crashpad_client_win.cc(810)] not connected
[1031/085527.626:ERROR:crashpad_client_win.cc(810)] not connected
[1031/085529.576:ERROR:crashpad_client_win.cc(810)] not connected
26 changes: 24 additions & 2 deletions packages/ui/src/components/BooleanCard/BooleanCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import React from "react"
import type { Meta } from "@storybook/react"

import { cn } from "../../helpers"
import { BooleanCard } from "./index"
import { useBoolean } from "../../hooks"
import { Button } from "../Button"
import { BooleanCard, LoadingBooleanCard } from "./index"

const meta: Meta<typeof BooleanCard> = {
title: "Components/BooleanCard",
Expand Down Expand Up @@ -108,7 +110,7 @@ export const CustomDescription = () => {
return (
<div className="flex gap-2 flex-col">
<span>Custom description</span>
<span className="text-xs text-secondary">
<span className="text-xs text-secondary-600">
This is a custom description
</span>
<div className="flex gap-2 items-center">
Expand All @@ -135,3 +137,23 @@ export const CustomDescription = () => {
</div>
)
}

export const Loading = () => {
const { value: isLoading, toggle } = useBoolean(false)

return (
<div className="flex flex-col gap-4 max-w-sm">
<Button onClick={toggle}>{isLoading ? "Stop" : "Start"} loading</Button>
{isLoading ? (
<LoadingBooleanCard />
) : (
<BooleanCard
title="Remember me"
description="Your account will be saved"
checked={isLoading}
onChange={toggle}
/>
)}
</div>
)
}
16 changes: 12 additions & 4 deletions packages/ui/src/components/BooleanCard/BooleanCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,18 @@ export const BooleanCard = ({

return (
<Card
className={cn("cursor-pointer transition-colors h-fit w-full", {
className={cn("text-left cursor-pointer transition-colors h-fit w-full", {
"bg-secondary-50": innerChecked,
})}
onClick={() => handleChange(!innerChecked)}
>
<div className="flex justify-between gap-4 w-full">
<div className="flex justify-between gap-6 w-full">
<header className="flex flex-col gap-1 w-full">
<strong
className={cn("text-medium", rest.titleProps?.className)}
className={cn(
"text-medium text-balance",
rest.titleProps?.className
)}
{...rest.titleProps}
>
{title}
Expand All @@ -54,7 +57,12 @@ export const BooleanCard = ({
</p>
</header>

<Switch {...rest} checked={innerChecked} onChange={handleChange} />
<Switch
tabIndex={-1}
{...rest}
checked={innerChecked}
onChange={handleChange}
/>
</div>
</Card>
)
Expand Down
24 changes: 13 additions & 11 deletions packages/ui/src/components/BooleanCard/LoadingBooleanCard.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { Card } from '../Card'
import { Switch } from '../Switch'
import { Card } from "../Card"
import { Switch } from "../Switch"

export const SuggestionLoadingCard = () => {
export const LoadingBooleanCard = () => {
return (
<li className="opacity-60 animate-pulse">
<div className="opacity-60 animate-pulse">
<Card>
<div className="flex justify-between gap-4 w-full">
<div className="flex justify-between gap-6 w-full">
<header className="flex flex-col gap-1 w-full">
<h4 className="bg-secondary/40 w-fit rounded-full text-transparent">lorem pisum lorem</h4>
<h5 className="text-sm w-fit bg-secondary/20 rounded-full text-transparent">lorem pisum lorem epson</h5>
<h4 className="bg-secondary/40 w-fit rounded-full text-transparent">
lorem pisum lorem
</h4>
<h5 className="text-sm w-fit bg-secondary/20 rounded-full text-transparent">
lorem pisum lorem epson
</h5>
</header>

<div>
<Switch disabled checked={false} onChange={() => {}} />
</div>
<Switch disabled checked={false} onChange={() => {}} />
</div>
</Card>
</li>
</div>
)
}
33 changes: 18 additions & 15 deletions packages/ui/src/components/Breadcrumb/Breadcrumb.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import type { Meta, StoryFn } from '@storybook/react'
import type { BreadcrumbComponentProps } from './Breadcrumb'
import { Breadcrumb } from './Breadcrumb'
import { BreadcrumbItem } from './BreadcrumbItem'
import { TbHome, TbUser } from 'react-icons/tb'
import type { Meta, StoryFn } from "@storybook/react"
import { HiOutlineChevronRight } from "react-icons/hi"
import { TbHome, TbUser } from "react-icons/tb"

import { Dropdown, DropdownItem } from '../Dropdown'
import { HiOutlineChevronRight } from 'react-icons/hi'
import { Dropdown, DropdownItem } from "../Dropdown"
import { Breadcrumb, type BreadcrumbComponentProps } from "./Breadcrumb"
import { BreadcrumbItem } from "./BreadcrumbItem"

export default {
title: 'Components/Breadcrumb',
title: "Components/Breadcrumb",
component: Breadcrumb,
tags: ['autodocs'],
tags: ["autodocs"],
decorators: [
Story => (
(Story) => (
<div className="flex p-6 flex-col ">
<Story />
</div>
),
],
parameters: {
layout: 'fullscreen',
layout: "fullscreen",
},
} as Meta

const Template: StoryFn<BreadcrumbComponentProps> = args => (
const Template: StoryFn<BreadcrumbComponentProps> = (args) => (
<Breadcrumb {...args}>
<BreadcrumbItem href="https://polgubau.com/" icon={TbHome}>
Home
Expand All @@ -33,7 +32,11 @@ const Template: StoryFn<BreadcrumbComponentProps> = args => (
</BreadcrumbItem>
<HiOutlineChevronRight className="text-secondary-600 ml-2" />

<Dropdown label={'...'} className="bg-transparent text-secondary-900">
<Dropdown
defaultTriggerOptions={{ variant: "ghost" }}
label={"..."}
className="bg-transparent text-secondary-900"
>
<DropdownItem label="Authors" />
<DropdownItem label="Selected" />
<DropdownItem label="Matched" />
Expand All @@ -46,7 +49,7 @@ const Template: StoryFn<BreadcrumbComponentProps> = args => (
export const Default = Template.bind({})

export const SolidBackground = Template.bind({})
SolidBackground.storyName = 'Solid background'
SolidBackground.storyName = "Solid background"
SolidBackground.args = {
className: 'bg-primary-400 w-fit py-2 px-4 rounded-xl',
className: "bg-primary-400 w-fit py-2 px-4 rounded-xl",
}
24 changes: 5 additions & 19 deletions packages/ui/src/components/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
import type { Meta, StoryFn } from "@storybook/react"
import type { Meta } from "@storybook/react"

import { toast } from "../Toaster"
import { Card, type CardProps } from "./Card"
import { Card } from "./Card"

export default {
title: "Components/Card",
component: Card,
tags: ["autodocs"],
} as Meta

const Template: StoryFn<CardProps> = (args: CardProps) => (
<Card {...args}>
<h5 className="text-2xl font-bold tracking-tight text-black dark:text-white">
Check this Card title!
</h5>
<p className="font-normal text-secondary-700 dark:text-secondary-400">
This components is quite flexible and can be used in many ways. Customize
it to your needs!
</p>
</Card>
)

export const Default = Template.bind({})
Default.args = { className: "max-w-sm" }

export const LinkCard = () => {
export const Default = () => {
return (
<Card href="#">
<Card>
<h5 className="text-2xl font-bold tracking-tight text-black dark:text-white">
Check this Card title!
</h5>
Expand All @@ -37,6 +22,7 @@ export const LinkCard = () => {
</Card>
)
}

export const ButtonCard = () => {
return (
<Card
Expand Down
76 changes: 44 additions & 32 deletions packages/ui/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,72 @@
"use client"

import type { ComponentProps, FC } from "react"
import React, { type ComponentProps, type FC } from "react"

import { cn } from "../../helpers"
import { cn, mergeRefs } from "../../helpers"
import { mergeDeep } from "../../helpers/merge-deep/merge-deep"
import { useRipple } from "../../hooks"
import { getTheme } from "../../theme-store"
import type { DeepPartial } from "../../types/types"
import { ButtonProps } from "../Button"
import { FocusEffect } from "../FocusEffect"
import type { CardTheme } from "./theme"

export type CardProps = ComponentProps<"div"> &
ComponentProps<"button"> &
ComponentProps<"a"> & {
href?: string
Pick<ButtonProps, "rippleOptions"> & {
theme?: DeepPartial<CardTheme>
onClick?: () => void
}

/**
* @name Card
*
* @description A Card component that can be used to display content in a card-like style. Usefull in a blog, a social network, a forum...
*
* @returns {React.ReactNode} A Card component.
*
* @example
* @example ```
* <Card>
* <h5 className="text-2xl font-bold">Card title!</h5>
* <p className="font-normal text-secondary-700">
* Hello there!
* </p>
* </Card>
* ```
* @returns {React.ReactNode} A Card component.
*
*/
export const Card: FC<CardProps> = (props): React.ReactNode => {
const { href, theme: customTheme = {}, onClick, ...rest } = props

// Card component will be an Anchor link if href prop is passed.

const Component =
typeof onClick === "undefined"
? typeof href === "undefined"
? "div"
: "a"
: "button"

const theme = mergeDeep(getTheme().card, customTheme)
return (
<Component
data-testid="ui-card"
href={href}
onClick={onClick}
className={cn(theme.base, href && theme.href, rest?.className)}
{...(rest as any)}
>
{rest.children}
{onClick && <FocusEffect />}
</Component>
)
}

export const Card = React.forwardRef<React.ElementRef<"div">, CardProps>(
(props, ref) => {
const { theme: customTheme = {}, onClick, className = "", ...rest } = props

// Card component will be an Anchor link if href prop is passed.

const Component = typeof onClick === "undefined" ? "div" : "button"

const theme = mergeDeep(getTheme().card, customTheme)

const [ripple, event] = useRipple({
disabled: rest.disabled,
...rest.rippleOptions,
opacity: 0.3,
})
return (
<Component
ref={mergeRefs([ripple, ref])}
data-testid="ui-card"
onClick={(e) => {
if (onClick) {
event(e)
onClick(e as React.MouseEvent<HTMLButtonElement>)
}
}}
className={cn(theme.base, className)}
{...(rest as any)}
>
{rest.children}
{onClick && <FocusEffect />}
</Component>
)
}
)
5 changes: 1 addition & 4 deletions packages/ui/src/components/Card/theme.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
export interface CardTheme {
base: string
href: string
}

export const cardTheme: CardTheme = {
base: "flex flex-col gap-2 rounded-xl bg-secondary/40 gap-2 p-4 group",

href: "hover:bg-secondary-100 dark:hover:bg-secondary-700",
base: "h-fit flex-col gap-2 rounded-xl bg-secondary-100 dark:bg-secondary-800/80 text-secondary-900 dark:text-secondary-50 shadow gap-2 p-4 group text-left",
}
10 changes: 8 additions & 2 deletions packages/ui/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as D from "@radix-ui/react-dropdown-menu"
import { TbCheck, TbCircle } from "react-icons/tb"

import { cn } from "../../helpers"
import { Button } from "../Button"
import { Button, ButtonProps } from "../Button"
import { DropdownContent } from "./components"

export interface DropdownProps extends D.DropdownMenuContentProps {
Expand All @@ -19,16 +19,22 @@ export interface DropdownProps extends D.DropdownMenuContentProps {
/** Label of the trigger button, if you don't provide a custom trigger */
label?: string
disabled?: boolean
defaultTriggerOptions?: ButtonProps
}

const Dropdown = ({
trigger,
label = "Open Menu",
children,
disabled,
defaultTriggerOptions,
...props
}: DropdownProps) => {
const triggerNode = trigger ?? <Button name={label}>{label}</Button>
const triggerNode = trigger ?? (
<Button {...defaultTriggerOptions} name={label}>
{label}
</Button>
)
return (
<D.Root>
<D.Trigger disabled={disabled} asChild>
Expand Down
4 changes: 4 additions & 0 deletions packages/ui/src/components/Switch/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client"

import {
useEffect,
useId,
useState,
type ComponentProps,
Expand Down Expand Up @@ -59,6 +60,9 @@ export const Switch: FC<SwitchProps> = ({
onChange?.(newValue)
setValue(newValue)
}
useEffect(() => {
setValue(checked)
}, [checked])

const handleOnKeyDown = (event: KeyboardEvent<HTMLButtonElement>): void => {
const code = event.code
Expand Down
Loading

0 comments on commit bd7bd51

Please sign in to comment.