diff --git a/.eslintrc.json b/.eslintrc.json index 4b0b528..4b738c4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -43,7 +43,18 @@ "html": true } ], - + // Reactの明示的なimportを禁止する + "no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "react", + "importNames": ["default"] + } + ] + } + ], // 型の名前をパスカルケースにする "@typescript-eslint/naming-convention": [ "error", diff --git a/.github/workflows/auto_merge.yml b/.github/workflows/auto_merge.yml index ee2b34e..fc66e4b 100644 --- a/.github/workflows/auto_merge.yml +++ b/.github/workflows/auto_merge.yml @@ -1,6 +1,8 @@ name: Dependabot auto-merge -on: pull_request - +on: + pull_request_target: + types: + - opened permissions: contents: write pull-requests: write @@ -15,9 +17,16 @@ jobs: uses: dependabot/fetch-metadata@v1 with: github-token: '${{ secrets.GITHUB_TOKEN }}' - - name: Enable auto-merge for Dependabot PRs + + - name: approve if: contains(steps.metadata.outputs.dependency-names, 'my-dependency') && steps.metadata.outputs.update-type == 'version-update:semver-patch' + + run: gh pr review --approve "$PR_URL" + + - name: Enable auto-merge for Dependabot PRs run: gh pr merge --auto --merge "$PR_URL" + env: PR_URL: ${{github.event.pull_request.html_url}} + GH_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/chromatic_deploy.yml b/.github/workflows/chromatic_deploy.yml index b2931ea..948852f 100644 --- a/.github/workflows/chromatic_deploy.yml +++ b/.github/workflows/chromatic_deploy.yml @@ -1,11 +1,13 @@ name: 'Chromatic' -on: push +on: + pull_request: + types: [opened, synchronize, reopened] jobs: chromatic-deployment: runs-on: ubuntu-latest - if: !contains(github.event.head_commit.message , 'dependabot') + if: github.event.pull_request.user.login != 'dependabot[bot]' steps: - uses: actions/checkout@v4 - name: Install dependencies diff --git a/package.json b/package.json index cbf01bd..739e517 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@commitlint/config-conventional": "^17.7.0", "@markuplint/jsx-parser": "^3.11.0", "@markuplint/react-spec": "^3.12.0", + "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-slot": "^1.0.2", "@stoplight/prism-cli": "^5.4.0", "@storybook/addon-essentials": "^7.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57bfda3..db139f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,6 +43,9 @@ devDependencies: '@markuplint/react-spec': specifier: ^3.12.0 version: 3.12.0(@markuplint/ml-core@3.13.0) + '@radix-ui/react-avatar': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.13)(@types/react@18.2.30)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.30)(react@18.2.0) @@ -3164,6 +3167,30 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true + /@radix-ui/react-avatar@1.0.4(@types/react-dom@18.2.13)(@types/react@18.2.30)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.30)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.30)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.30)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.30)(react@18.2.0) + '@types/react': 18.2.30 + '@types/react-dom': 18.2.13 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.30)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: diff --git a/src/components/ui/Avatar/index.stories.tsx b/src/components/ui/Avatar/index.stories.tsx new file mode 100644 index 0000000..8e09901 --- /dev/null +++ b/src/components/ui/Avatar/index.stories.tsx @@ -0,0 +1,32 @@ +import { Avatar, AvatarFallback, AvatarImage } from '.'; + +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + component: Avatar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + CN + + ), +}; + +export const Fallback: Story = { + render: () => ( + + CN + + ) +} diff --git a/src/components/ui/Avatar/index.test.tsx b/src/components/ui/Avatar/index.test.tsx new file mode 100644 index 0000000..038d4c2 --- /dev/null +++ b/src/components/ui/Avatar/index.test.tsx @@ -0,0 +1,35 @@ +import { render, screen } from '@testing-library/react'; + +import '@testing-library/jest-dom'; + +import { Avatar, AvatarFallback, AvatarImage } from '.'; + +describe('test ui/Avatar', () => { + it('renders Avatar correctly', () => { + const { container } = render(); + expect(container.firstChild).toHaveClass( + 'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full' + ); + }); + + it('renders Avatar with AvatarImage, AvatarFallback correctly', () => { + const fallbackText = 'FB'; + const imageUrl = 'https://github.com/shadcn.png' + render( + + + {fallbackText} + + ); + + const fallback = screen.getByText(fallbackText); + expect(fallback).toBeInTheDocument(); + expect(fallback).toHaveClass( + 'flex h-full w-full items-center justify-center rounded-full bg-muted' + ); + + expect(fallback.parentElement).toHaveClass( + 'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full' + ); + }); +}); diff --git a/src/components/ui/Avatar/index.tsx b/src/components/ui/Avatar/index.tsx new file mode 100644 index 0000000..a43467a --- /dev/null +++ b/src/components/ui/Avatar/index.tsx @@ -0,0 +1,51 @@ +'use client'; + +import { forwardRef } from 'react'; + +import * as AvatarPrimitive from '@radix-ui/react-avatar'; + +import { cn } from '@/libs/utils'; + +const Avatar = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/src/components/ui/Tag/index.tsx b/src/components/ui/Tag/index.tsx index 6be84aa..ab74890 100644 --- a/src/components/ui/Tag/index.tsx +++ b/src/components/ui/Tag/index.tsx @@ -1,5 +1,4 @@ import type { FC, HTMLAttributes, ReactNode } from 'react'; -import React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; import Link from 'next/link';