diff --git a/pkgs/clan-app/ui/package.json b/pkgs/clan-app/ui/package.json index 1d30e84b8..649a7e54d 100644 --- a/pkgs/clan-app/ui/package.json +++ b/pkgs/clan-app/ui/package.json @@ -28,10 +28,8 @@ "@storybook/addon-a11y": "^9.0.8", "@storybook/addon-docs": "^9.0.8", "@storybook/addon-links": "^9.0.8", - "@storybook/addon-onboarding": "^9.0.8", "@storybook/addon-viewport": "^9.0.8", "@storybook/addon-vitest": "^9.0.8", - "@tailwindcss/typography": "^0.5.13", "@types/node": "^22.15.19", "@types/three": "^0.176.0", "@typescript-eslint/parser": "^8.32.1", @@ -68,7 +66,6 @@ "@modular-forms/solid": "^0.25.1", "@solid-primitives/storage": "^4.3.2", "@solidjs/router": "^0.15.3", - "@solidjs/testing-library": "^0.8.10", "@tanstack/eslint-plugin-query": "^5.51.12", "@tanstack/solid-query": "^5.76.0", "solid-js": "^1.9.7", diff --git a/pkgs/clan-app/ui/src/components/v2/Tag/Tag.css b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.css new file mode 100644 index 000000000..8c7d2c51c --- /dev/null +++ b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.css @@ -0,0 +1,37 @@ +span.tag { + @apply flex items-center gap-1 w-fit px-2 py-1 rounded-full; + @apply bg-def-4; + + &:focus-visible { + @apply bg-def-acc-3 outline-none; + box-shadow: + 0 0 0 0.0625rem theme(colors.off.white), + 0 0 0 0.125rem theme(colors.border.semantic.info.1); + } + + &.active { + @apply bg-def-acc-4; + } + + &.inverted { + @apply bg-inv-1; + } + + &.has-action { + @apply pr-1.5; + + &:hover { + @apply bg-def-acc-3; + } + + &.inverted:hover { + @apply bg-inv-acc-3; + } + } + + & > .icon { + &:hover { + @apply cursor-pointer; + } + } +} diff --git a/pkgs/clan-app/ui/src/components/v2/Tag/Tag.stories.tsx b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.stories.tsx new file mode 100644 index 000000000..29665e402 --- /dev/null +++ b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.stories.tsx @@ -0,0 +1,47 @@ +import { Tag, TagProps } from "@/src/components/v2/Tag/Tag"; +import { Meta, type StoryContext, StoryObj } from "@kachurun/storybook-solid"; +import { expect, fn } from "storybook/test"; + +const meta: Meta = { + title: "Components/Tag", + component: Tag, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + label: "Label", + }, +}; + +export const WithAction: Story = { + args: { + ...Default.args, + action: { + icon: "Close", + onClick: fn(), + }, + }, + play: async ({ canvas, step, userEvent, args }: StoryContext) => { + await userEvent.click(canvas.getByRole("button")); + await expect(args.action.onClick).toHaveBeenCalled(); + }, +}; + +export const Inverted: Story = { + args: { + label: "Label", + inverted: true, + }, +}; + +export const InvertedWithAction: Story = { + args: { + ...WithAction.args, + inverted: true, + }, + play: WithAction.play, +}; diff --git a/pkgs/clan-app/ui/src/components/v2/Tag/Tag.tsx b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.tsx new file mode 100644 index 000000000..fe8657480 --- /dev/null +++ b/pkgs/clan-app/ui/src/components/v2/Tag/Tag.tsx @@ -0,0 +1,54 @@ +import "./Tag.css"; + +import cx from "classnames"; +import { Typography } from "@/src/components/v2/Typography/Typography"; +import { createSignal, Show } from "solid-js"; +import Icon, { IconVariant } from "../Icon/Icon"; + +export interface TagAction { + icon: IconVariant; + onClick: () => void; +} + +export interface TagProps { + label: string; + action?: TagAction; + inverted?: boolean; +} + +export const Tag = (props: TagProps) => { + const inverted = () => props.inverted || false; + + const [isActive, setIsActive] = createSignal(false); + + const handleActionClick = () => { + setIsActive(true); + props.action?.onClick(); + setTimeout(() => setIsActive(false), 150); + }; + + return ( + + + {props.label} + + + + + + ); +};