diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ec75ed30..aea7fb27a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,6 +88,7 @@ the macOS native vibrancy material, which Chromium cannot render. ### 🎨 Code Style & Conventions - Linting and formatting are configured in `vite.config.mts` (the `lint` and `fmt` blocks). Please run `pnpm check` before submitting a PR. +- Renderer React components are defined as function declarations. `React.FC` is reserved for typing a component value (a prop or return type), never a component definition; `react/function-component-definition` enforces this. - Follow existing file and folder naming conventions. - See [ARCHITECTURE.md](./ARCHITECTURE.md) for the renderer's module layering, state ownership, and side-effect conventions. - Keep commit messages clear and descriptive. diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 135053ab6..19f4e11ef 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -42,7 +42,7 @@ function RequireAuth({ children }: { children: React.ReactNode }) { return isLoggedIn ? children : ; } -export const App = () => { +export function App() { // Initialize store subscriptions with proper cleanup useEffect(() => { const cleanup = initializeStoreSubscriptions(); @@ -128,4 +128,4 @@ export const App = () => { ); -}; +} diff --git a/src/renderer/components/AllRead.tsx b/src/renderer/components/AllRead.tsx index 608655e8c..2d26162e0 100644 --- a/src/renderer/components/AllRead.tsx +++ b/src/renderer/components/AllRead.tsx @@ -1,4 +1,4 @@ -import { type FC, useMemo } from 'react'; +import { useMemo } from 'react'; import { Constants } from '../constants'; @@ -12,7 +12,7 @@ interface AllReadProps { fullHeight?: boolean; } -export const AllRead: FC = ({ fullHeight = true }: AllReadProps) => { +export function AllRead({ fullHeight = true }: AllReadProps) { const hasFilters = useFiltersStore((s) => s.hasActiveFilters()); const emoji = useMemo(() => randomElement(Constants.EMOJIS.ALL_READ), []); @@ -20,4 +20,4 @@ export const AllRead: FC = ({ fullHeight = true }: AllReadProps) = const heading = `No new ${hasFilters ? 'filtered ' : ''} notifications`; return ; -}; +} diff --git a/src/renderer/components/GlobalEffects.tsx b/src/renderer/components/GlobalEffects.tsx index f44699a31..235096bb4 100644 --- a/src/renderer/components/GlobalEffects.tsx +++ b/src/renderer/components/GlobalEffects.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect } from 'react'; +import { useEffect } from 'react'; import { useQueryClient } from '@tanstack/react-query'; @@ -23,7 +23,7 @@ import { setTrayIconColorAndTitle } from '../utils/system/tray'; * Owns: theme application, tray icon updates, global shortcut registration, * app reset handling, periodic account refreshes, and notification alerts. */ -export const GlobalEffects: FC = () => { +export function GlobalEffects() { const queryClient = useQueryClient(); const resetAccounts = useAccountsStore((s) => s.reset); @@ -74,4 +74,4 @@ export const GlobalEffects: FC = () => { }, [resetAccounts, resetSettings, resetFilters, queryClient]); return null; -}; +} diff --git a/src/renderer/components/GlobalShortcuts.tsx b/src/renderer/components/GlobalShortcuts.tsx index ef1390ad1..f15626317 100644 --- a/src/renderer/components/GlobalShortcuts.tsx +++ b/src/renderer/components/GlobalShortcuts.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect } from 'react'; +import { useEffect } from 'react'; import { useShortcutActions } from '../hooks/useShortcutActions'; @@ -8,7 +8,7 @@ import { getNormalizedKey, shouldIgnoreKeyboardEvent } from '../utils/ui/keyboar * Component that registers global keyboard shortcuts for the renderer app. * Mount once inside App, within Router + AppProvider. */ -export const GlobalShortcuts: FC = () => { +export function GlobalShortcuts() { const { shortcuts } = useShortcutActions(); useEffect(() => { @@ -41,4 +41,4 @@ export const GlobalShortcuts: FC = () => { }, [shortcuts]); return null; -}; +} diff --git a/src/renderer/components/Oops.tsx b/src/renderer/components/Oops.tsx index 89a379ef2..51f86bb0c 100644 --- a/src/renderer/components/Oops.tsx +++ b/src/renderer/components/Oops.tsx @@ -1,4 +1,4 @@ -import { type FC, useMemo } from 'react'; +import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from '@primer/react'; @@ -15,7 +15,7 @@ interface OopsProps { fullHeight?: boolean; } -export const Oops: FC = ({ error, fullHeight = true }: OopsProps) => { +export function Oops({ error, fullHeight = true }: OopsProps) { const navigate = useNavigate(); const err = error ?? Errors.UNKNOWN; @@ -44,4 +44,4 @@ export const Oops: FC = ({ error, fullHeight = true }: OopsProps) => subHeadings={err.descriptions} /> ); -}; +} diff --git a/src/renderer/components/Sidebar.tsx b/src/renderer/components/Sidebar.tsx index 2e3c38941..159126a64 100644 --- a/src/renderer/components/Sidebar.tsx +++ b/src/renderer/components/Sidebar.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { BellIcon, CrosshairsIcon, @@ -21,7 +19,7 @@ import { useAccountsStore, useFiltersStore, useSettingsStore } from '../stores'; import { LogoIcon } from '../icons/LogoIcon'; -export const Sidebar: FC = () => { +export function Sidebar() { const { status, notificationCount, hasUnreadNotifications, isFetching } = useNotifications(); const { shortcuts } = useShortcutActions(); @@ -165,4 +163,4 @@ export const Sidebar: FC = () => { ); -}; +} diff --git a/src/renderer/components/avatars/AvatarWithFallback.tsx b/src/renderer/components/avatars/AvatarWithFallback.tsx index 01344aeaf..eb277ec76 100644 --- a/src/renderer/components/avatars/AvatarWithFallback.tsx +++ b/src/renderer/components/avatars/AvatarWithFallback.tsx @@ -1,4 +1,3 @@ -import type React from 'react'; import type { FC } from 'react'; import { createElement, useState } from 'react'; @@ -20,14 +19,14 @@ export interface AvatarWithFallbackProps { icon?: FC; } -export const AvatarWithFallback: React.FC = ({ +export function AvatarWithFallback({ src, alt, name, size = Size.MEDIUM, userType = 'User', icon, -}) => { +}: AvatarWithFallbackProps) { const [hasBrokenAvatarSource, setHasBrokenAvatarSource] = useState(false); const isNonHuman = isNonHumanUser(userType); @@ -54,4 +53,4 @@ export const AvatarWithFallback: React.FC = ({ )} ); -}; +} diff --git a/src/renderer/components/fields/Checkbox.tsx b/src/renderer/components/fields/Checkbox.tsx index 3b21f7c7d..1cf5a0861 100644 --- a/src/renderer/components/fields/Checkbox.tsx +++ b/src/renderer/components/fields/Checkbox.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -19,7 +19,7 @@ export interface CheckboxProps { onChange: (evt: React.ChangeEvent) => void; } -export const Checkbox: FC = ({ visible = true, ...props }: CheckboxProps) => { +export function Checkbox({ visible = true, ...props }: CheckboxProps) { const counter = props?.counter === 0 ? '0' : props.counter; return ( @@ -53,4 +53,4 @@ export const Checkbox: FC = ({ visible = true, ...props }: Checkb ) ); -}; +} diff --git a/src/renderer/components/fields/FieldLabel.tsx b/src/renderer/components/fields/FieldLabel.tsx index 4d9dec3a4..4c09203ce 100644 --- a/src/renderer/components/fields/FieldLabel.tsx +++ b/src/renderer/components/fields/FieldLabel.tsx @@ -1,14 +1,12 @@ -import type { FC } from 'react'; - export interface FieldLabelProps { name: string; label: string; } -export const FieldLabel: FC = (props: FieldLabelProps) => { +export function FieldLabel(props: FieldLabelProps) { return ( ); -}; +} diff --git a/src/renderer/components/fields/RadioGroup.tsx b/src/renderer/components/fields/RadioGroup.tsx index aa6635bfb..8d8cd27de 100644 --- a/src/renderer/components/fields/RadioGroup.tsx +++ b/src/renderer/components/fields/RadioGroup.tsx @@ -1,4 +1,4 @@ -import type { ChangeEvent, FC, ReactNode } from 'react'; +import type { ChangeEvent, ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -16,7 +16,7 @@ export interface RadioGroupProps { tooltip?: ReactNode | string; } -export const RadioGroup: FC = (props: RadioGroupProps) => { +export function RadioGroup(props: RadioGroupProps) { return ( @@ -44,4 +44,4 @@ export const RadioGroup: FC = (props: RadioGroupProps) => { {props.tooltip && } ); -}; +} diff --git a/src/renderer/components/fields/Tooltip.tsx b/src/renderer/components/fields/Tooltip.tsx index 1c340ca2d..07ff3a163 100644 --- a/src/renderer/components/fields/Tooltip.tsx +++ b/src/renderer/components/fields/Tooltip.tsx @@ -1,4 +1,4 @@ -import { type FC, type ReactNode, useEffect, useRef, useState } from 'react'; +import { type ReactNode, useEffect, useRef, useState } from 'react'; import { QuestionIcon } from '@primer/octicons-react'; import { AnchoredOverlay } from '@primer/react'; @@ -10,7 +10,7 @@ export interface TooltipProps { tooltip: ReactNode | string; } -export const Tooltip: FC = (props: TooltipProps) => { +export function Tooltip(props: TooltipProps) { const [shouldShowTooltipContents, setShouldShowTooltipContents] = useState(false); const scrollContainerRef = useRef(null); @@ -100,4 +100,4 @@ export const Tooltip: FC = (props: TooltipProps) => { ); -}; +} diff --git a/src/renderer/components/filters/AccountFilter.tsx b/src/renderer/components/filters/AccountFilter.tsx index ff452e7d7..8a9ffbec0 100644 --- a/src/renderer/components/filters/AccountFilter.tsx +++ b/src/renderer/components/filters/AccountFilter.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { PersonIcon } from '@primer/octicons-react'; import { Stack, Text } from '@primer/react'; @@ -11,7 +9,7 @@ import { Title } from '../primitives/Title'; import { getAccountUUID } from '../../utils/auth/utils'; -export const AccountFilter: FC = () => { +export function AccountFilter() { const { notifications } = useNotifications(); const accounts = useAccountsStore((s) => s.accounts); const filteredAccounts = useFiltersStore((s) => s.accounts); @@ -46,4 +44,4 @@ export const AccountFilter: FC = () => { ); -}; +} diff --git a/src/renderer/components/filters/FilterSection.tsx b/src/renderer/components/filters/FilterSection.tsx index f5f946071..6a673c677 100644 --- a/src/renderer/components/filters/FilterSection.tsx +++ b/src/renderer/components/filters/FilterSection.tsx @@ -22,7 +22,7 @@ export interface FilterSectionProps { layout?: 'horizontal' | 'vertical'; } -const FilterSectionComponent = ({ +function FilterSectionComponent({ id, title, icon, @@ -30,7 +30,7 @@ const FilterSectionComponent = ({ filterSetting, tooltip, layout = 'vertical', -}: FilterSectionProps) => { +}: FilterSectionProps) { const { notifications } = useNotifications(); const updateFilter = useFiltersStore((s) => s.updateFilter); @@ -102,7 +102,7 @@ const FilterSectionComponent = ({ ); -}; +} // Memoize the component to prevent unnecessary re-renders export const FilterSection = memo(FilterSectionComponent) as typeof FilterSectionComponent; diff --git a/src/renderer/components/filters/ReasonFilter.tsx b/src/renderer/components/filters/ReasonFilter.tsx index d3e3b5a30..6b20b2c43 100644 --- a/src/renderer/components/filters/ReasonFilter.tsx +++ b/src/renderer/components/filters/ReasonFilter.tsx @@ -1,12 +1,10 @@ -import type { FC } from 'react'; - import { NoteIcon } from '@primer/octicons-react'; import { Text } from '@primer/react'; import { reasonFilter } from '../../utils/notifications/filters'; import { FilterSection } from './FilterSection'; -export const ReasonFilter: FC = () => { +export function ReasonFilter() { return ( { tooltip={Filter notifications by reason.} /> ); -}; +} diff --git a/src/renderer/components/filters/RequiresDetailedNotificationsWarning.tsx b/src/renderer/components/filters/RequiresDetailedNotificationsWarning.tsx index df4c8efd3..8b24d7987 100644 --- a/src/renderer/components/filters/RequiresDetailedNotificationsWarning.tsx +++ b/src/renderer/components/filters/RequiresDetailedNotificationsWarning.tsx @@ -1,10 +1,10 @@ -import type { FC } from 'react'; - import { Text } from '@primer/react'; -export const RequiresDetailedNotificationWarning: FC = () => ( - - ⚠️ This filter requires the Detailed Notifications setting to be - enabled. - -); +export function RequiresDetailedNotificationWarning() { + return ( + + ⚠️ This filter requires the Detailed Notifications setting to be + enabled. + + ); +} diff --git a/src/renderer/components/filters/ReviewRequestTypeFilter.tsx b/src/renderer/components/filters/ReviewRequestTypeFilter.tsx index cd30768fe..dcbce054c 100644 --- a/src/renderer/components/filters/ReviewRequestTypeFilter.tsx +++ b/src/renderer/components/filters/ReviewRequestTypeFilter.tsx @@ -1,12 +1,10 @@ -import type { FC } from 'react'; - import { GitPullRequestIcon } from '@primer/octicons-react'; import { Stack, Text } from '@primer/react'; import { reviewRequestTypeFilter } from '../../utils/notifications/filters'; import { FilterSection } from './FilterSection'; -export const ReviewRequestTypeFilter: FC = () => { +export function ReviewRequestTypeFilter() { return ( { } /> ); -}; +} diff --git a/src/renderer/components/filters/SearchFilter.tsx b/src/renderer/components/filters/SearchFilter.tsx index 3fa33a92e..961fc083d 100644 --- a/src/renderer/components/filters/SearchFilter.tsx +++ b/src/renderer/components/filters/SearchFilter.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { CheckCircleFillIcon, CommentIcon, @@ -27,7 +25,7 @@ import { import { RequiresDetailedNotificationWarning } from './RequiresDetailedNotificationsWarning'; import { TokenSearchInput } from './TokenSearchInput'; -export const SearchFilter: FC = () => { +export function SearchFilter() { const updateFilter = useFiltersStore((s) => s.updateFilter); const includeSearchTokens = useFiltersStore((s) => s.includeSearchTokens); const excludeSearchTokens = useFiltersStore((s) => s.excludeSearchTokens); @@ -136,4 +134,4 @@ export const SearchFilter: FC = () => { ); -}; +} diff --git a/src/renderer/components/filters/SearchFilterSuggestions.tsx b/src/renderer/components/filters/SearchFilterSuggestions.tsx index ee211908d..639e1ca20 100644 --- a/src/renderer/components/filters/SearchFilterSuggestions.tsx +++ b/src/renderer/components/filters/SearchFilterSuggestions.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { Popover, Stack, Text } from '@primer/react'; import { cn } from 'cn'; @@ -19,7 +17,7 @@ interface SearchFilterSuggestionsProps { inputValue: string; } -export const SearchFilterSuggestions: FC = ({ open, inputValue }) => { +export function SearchFilterSuggestions({ open, inputValue }: SearchFilterSuggestionsProps) { const detailedNotifications = useSettingsStore((s) => s.detailedNotifications); if (!open) { @@ -56,4 +54,4 @@ export const SearchFilterSuggestions: FC = ({ open ); -}; +} diff --git a/src/renderer/components/filters/StateFilter.tsx b/src/renderer/components/filters/StateFilter.tsx index 83d1797d3..92de2fc6f 100644 --- a/src/renderer/components/filters/StateFilter.tsx +++ b/src/renderer/components/filters/StateFilter.tsx @@ -1,12 +1,10 @@ -import type { FC } from 'react'; - import { IssueOpenedIcon } from '@primer/octicons-react'; import { Text } from '@primer/react'; import { stateFilter } from '../../utils/notifications/filters'; import { FilterSection } from './FilterSection'; -export const StateFilter: FC = () => { +export function StateFilter() { return ( { tooltip={Filter notifications by state.} /> ); -}; +} diff --git a/src/renderer/components/filters/SubjectTypeFilter.tsx b/src/renderer/components/filters/SubjectTypeFilter.tsx index 4d57fba97..5f9161abb 100644 --- a/src/renderer/components/filters/SubjectTypeFilter.tsx +++ b/src/renderer/components/filters/SubjectTypeFilter.tsx @@ -1,12 +1,10 @@ -import type { FC } from 'react'; - import { BellIcon } from '@primer/octicons-react'; import { Text } from '@primer/react'; import { subjectTypeFilter } from '../../utils/notifications/filters'; import { FilterSection } from './FilterSection'; -export const SubjectTypeFilter: FC = () => { +export function SubjectTypeFilter() { return ( { tooltip={Filter notifications by type.} /> ); -}; +} diff --git a/src/renderer/components/filters/TokenSearchInput.tsx b/src/renderer/components/filters/TokenSearchInput.tsx index 3ea8b0c7a..2a9172e6e 100644 --- a/src/renderer/components/filters/TokenSearchInput.tsx +++ b/src/renderer/components/filters/TokenSearchInput.tsx @@ -19,7 +19,7 @@ interface TokenSearchInputProps { const INPUT_KEY_EVENTS: Set = new Set(['Enter', 'Tab', ' ', ',']); -export const TokenSearchInput: FC = ({ +export function TokenSearchInput({ label, icon: Icon, iconColorClass, @@ -27,7 +27,7 @@ export const TokenSearchInput: FC = ({ showSuggestionsOnFocusIfEmpty, onAdd, onRemove, -}) => { +}: TokenSearchInputProps) { const [inputValue, setInputValue] = useState(''); const [shouldShowFilterSuggestions, setShouldShowFilterSuggestions] = useState(false); @@ -103,4 +103,4 @@ export const TokenSearchInput: FC = ({ ); -}; +} diff --git a/src/renderer/components/filters/UserTypeFilter.tsx b/src/renderer/components/filters/UserTypeFilter.tsx index d6c09fcf2..3bbdd1442 100644 --- a/src/renderer/components/filters/UserTypeFilter.tsx +++ b/src/renderer/components/filters/UserTypeFilter.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { DependabotIcon, FeedPersonIcon, @@ -13,7 +11,7 @@ import { Size } from '../../types'; import { userTypeFilter } from '../../utils/notifications/filters'; import { FilterSection } from './FilterSection'; -export const UserTypeFilter: FC = () => { +export function UserTypeFilter() { return ( { } /> ); -}; +} diff --git a/src/renderer/components/layout/AppLayout.tsx b/src/renderer/components/layout/AppLayout.tsx index 3abf7d653..0fae4ed07 100644 --- a/src/renderer/components/layout/AppLayout.tsx +++ b/src/renderer/components/layout/AppLayout.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Sidebar } from '../Sidebar'; @@ -10,7 +10,7 @@ interface AppLayoutProps { * AppLayout is the main container for the application. * It handles the basic layout with sidebar and content area. */ -export const AppLayout: FC = ({ children }) => { +export function AppLayout({ children }: AppLayoutProps) { const setFocusRef = (el: HTMLButtonElement | null) => { if (el) { el.focus(); @@ -33,4 +33,4 @@ export const AppLayout: FC = ({ children }) => {
{children}
); -}; +} diff --git a/src/renderer/components/layout/Centered.tsx b/src/renderer/components/layout/Centered.tsx index f26c1b266..53d808c63 100644 --- a/src/renderer/components/layout/Centered.tsx +++ b/src/renderer/components/layout/Centered.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -7,7 +7,7 @@ interface CenteredProps { fullHeight: boolean; } -export const Centered: FC = (props: CenteredProps) => { +export function Centered(props: CenteredProps) { return ( = (props: CenteredProps) => { {props.children} ); -}; +} diff --git a/src/renderer/components/layout/Contents.tsx b/src/renderer/components/layout/Contents.tsx index 458a59a53..16eba41dc 100644 --- a/src/renderer/components/layout/Contents.tsx +++ b/src/renderer/components/layout/Contents.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { cn } from 'cn'; @@ -13,12 +13,12 @@ interface IContents { * Contents component holds the main content of a page. * It provides proper padding and handles scrolling. */ -export const Contents: FC = ({ +export function Contents({ children, paddingHorizontal = true, paddingBottom = false, scrollFade = false, -}) => { +}: IContents) { return (
= ({ {children}
); -}; +} diff --git a/src/renderer/components/layout/EmojiSplash.tsx b/src/renderer/components/layout/EmojiSplash.tsx index 5979bfcc6..d042d60bf 100644 --- a/src/renderer/components/layout/EmojiSplash.tsx +++ b/src/renderer/components/layout/EmojiSplash.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -14,7 +14,7 @@ interface EmojiSplashProps { actions?: ReactNode; } -export const EmojiSplash: FC = (props: EmojiSplashProps) => { +export function EmojiSplash(props: EmojiSplashProps) { return ( @@ -36,4 +36,4 @@ export const EmojiSplash: FC = (props: EmojiSplashProps) => { ); -}; +} diff --git a/src/renderer/components/layout/Page.tsx b/src/renderer/components/layout/Page.tsx index efdf1f56d..9b34d12c5 100644 --- a/src/renderer/components/layout/Page.tsx +++ b/src/renderer/components/layout/Page.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; interface PageProps { children: ReactNode; @@ -10,10 +10,10 @@ interface PageProps { * It creates a column layout for header, content, and footer. * The height is 100% to fill the parent container. */ -export const Page: FC = ({ children, testId }) => { +export function Page({ children, testId }: PageProps) { return (
{children}
); -}; +} diff --git a/src/renderer/components/login/LoginWithPersonalAccessTokenForm.tsx b/src/renderer/components/login/LoginWithPersonalAccessTokenForm.tsx index 38226b38b..59d552fc4 100644 --- a/src/renderer/components/login/LoginWithPersonalAccessTokenForm.tsx +++ b/src/renderer/components/login/LoginWithPersonalAccessTokenForm.tsx @@ -1,4 +1,4 @@ -import { type FC, type ReactNode, useCallback, useState } from 'react'; +import { type ReactNode, useCallback, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { BookIcon, EyeClosedIcon, EyeIcon, KeyIcon, SignInIcon } from '@primer/octicons-react'; @@ -61,7 +61,7 @@ export interface LoginWithPersonalAccessTokenFormProps { * Forge-specific route components (`routes/github`, `routes/gitea`) supply * their own copy via props so this form stays free of forge conditionals. */ -export const LoginWithPersonalAccessTokenForm: FC = ({ +export function LoginWithPersonalAccessTokenForm({ forge, title, hostnameCaption = '', @@ -75,7 +75,7 @@ export const LoginWithPersonalAccessTokenForm: FC { +}: LoginWithPersonalAccessTokenFormProps) { const navigate = useNavigate(); const location = useLocation(); const { account: reAuthAccount } = (location.state ?? {}) as LocationState; @@ -275,4 +275,4 @@ export const LoginWithPersonalAccessTokenForm: FC ); -}; +} diff --git a/src/renderer/components/metrics/CommentsPill.tsx b/src/renderer/components/metrics/CommentsPill.tsx index 9352cfb7e..f3161f211 100644 --- a/src/renderer/components/metrics/CommentsPill.tsx +++ b/src/renderer/components/metrics/CommentsPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { CommentIcon } from '@primer/octicons-react'; import { IconColor } from '../../types'; @@ -11,7 +9,7 @@ export interface CommentsPillProps { commentCount: number; } -export const CommentsPill: FC = ({ commentCount }) => { +export function CommentsPill({ commentCount }: CommentsPillProps) { if (!commentCount) { return null; } @@ -26,4 +24,4 @@ export const CommentsPill: FC = ({ commentCount }) => { metric={commentCount} /> ); -}; +} diff --git a/src/renderer/components/metrics/IssueTypesPill.tsx b/src/renderer/components/metrics/IssueTypesPill.tsx index 3cc3294d1..e9bc58399 100644 --- a/src/renderer/components/metrics/IssueTypesPill.tsx +++ b/src/renderer/components/metrics/IssueTypesPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { IssueOpenedIcon } from '@primer/octicons-react'; import type { GitifyIssueType } from '../../types'; @@ -10,10 +8,10 @@ export interface IssueTypesPillProps { issueType?: GitifyIssueType; } -export const IssueTypesPill: FC = ({ issueType }) => { +export function IssueTypesPill({ issueType }: IssueTypesPillProps) { if (!issueType) { return null; } return ; -}; +} diff --git a/src/renderer/components/metrics/LabelsPill.tsx b/src/renderer/components/metrics/LabelsPill.tsx index c0bcad6d5..05fecafe5 100644 --- a/src/renderer/components/metrics/LabelsPill.tsx +++ b/src/renderer/components/metrics/LabelsPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { TagIcon } from '@primer/octicons-react'; import { IssueLabelToken, LabelGroup } from '@primer/react'; @@ -12,7 +10,7 @@ export interface LabelsPillProps { issueFields?: GitifyIssueField[]; } -export const LabelsPill: FC = ({ labels, issueFields }) => { +export function LabelsPill({ labels, issueFields }: LabelsPillProps) { const fieldTokens = (issueFields ?? []).map((field) => ({ text: `${field.name}: ${field.value}`, fillColor: field.fillColor, @@ -54,4 +52,4 @@ export const LabelsPill: FC = ({ labels, issueFields }) => { metric={fieldTokens.length + (labels?.length ?? 0)} /> ); -}; +} diff --git a/src/renderer/components/metrics/LinkedIssuesPill.tsx b/src/renderer/components/metrics/LinkedIssuesPill.tsx index 4d147337f..a96cdab3a 100644 --- a/src/renderer/components/metrics/LinkedIssuesPill.tsx +++ b/src/renderer/components/metrics/LinkedIssuesPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { IssueRelatesToIcon } from '@primer/octicons-react'; import { IconColor } from '../../types'; @@ -11,7 +9,7 @@ export interface LinkedIssuesPillProps { linkedIssues: string[]; } -export const LinkedIssuesPill: FC = ({ linkedIssues }) => { +export function LinkedIssuesPill({ linkedIssues }: LinkedIssuesPillProps) { if (!linkedIssues?.length) { return null; } @@ -30,4 +28,4 @@ export const LinkedIssuesPill: FC = ({ linkedIssues }) => metric={linkedIssues.length} /> ); -}; +} diff --git a/src/renderer/components/metrics/MetricGroup.tsx b/src/renderer/components/metrics/MetricGroup.tsx index 6f8b5fe06..2979d59b2 100644 --- a/src/renderer/components/metrics/MetricGroup.tsx +++ b/src/renderer/components/metrics/MetricGroup.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { useSettingsStore } from '../../stores'; import type { GitifyNotification } from '../../types'; @@ -19,7 +17,7 @@ export interface MetricGroupProps { notification: GitifyNotification; } -export const MetricGroup: FC = ({ notification }) => { +export function MetricGroup({ notification }: MetricGroupProps) { const showPills = useSettingsStore((s) => s.showPills); if (!showPills) { @@ -61,4 +59,4 @@ export const MetricGroup: FC = ({ notification }) => { /> ); -}; +} diff --git a/src/renderer/components/metrics/MetricPill.tsx b/src/renderer/components/metrics/MetricPill.tsx index 6b6de1cfa..f8e6ea451 100644 --- a/src/renderer/components/metrics/MetricPill.tsx +++ b/src/renderer/components/metrics/MetricPill.tsx @@ -18,7 +18,7 @@ export interface MetricPillProps { ariaLabel?: string; } -export const MetricPill: FC = (props: MetricPillProps) => { +export function MetricPill(props: MetricPillProps) { const Icon = props.icon; return ( @@ -41,4 +41,4 @@ export const MetricPill: FC = (props: MetricPillProps) => { ); -}; +} diff --git a/src/renderer/components/metrics/MilestonePill.tsx b/src/renderer/components/metrics/MilestonePill.tsx index 5cbe99eb9..a33175a0d 100644 --- a/src/renderer/components/metrics/MilestonePill.tsx +++ b/src/renderer/components/metrics/MilestonePill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { MilestoneIcon } from '@primer/octicons-react'; import { type GitifyMilestone, IconColor } from '../../types'; @@ -10,7 +8,7 @@ export interface MilestonePillProps { milestone: GitifyMilestone; } -export const MilestonePill: FC = ({ milestone }) => { +export function MilestonePill({ milestone }: MilestonePillProps) { if (!milestone) { return null; } @@ -22,4 +20,4 @@ export const MilestonePill: FC = ({ milestone }) => { icon={MilestoneIcon} /> ); -}; +} diff --git a/src/renderer/components/metrics/ParentPill.tsx b/src/renderer/components/metrics/ParentPill.tsx index 6e695dc34..fce952711 100644 --- a/src/renderer/components/metrics/ParentPill.tsx +++ b/src/renderer/components/metrics/ParentPill.tsx @@ -1,4 +1,4 @@ -import type { FC, MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { IssueTrackedByIcon } from '@primer/octicons-react'; @@ -11,7 +11,7 @@ export interface ParentPillProps { parent?: GitifyParentIssue | null; } -export const ParentPill: FC = ({ parent }) => { +export function ParentPill({ parent }: ParentPillProps) { if (!parent) { return null; } @@ -32,4 +32,4 @@ export const ParentPill: FC = ({ parent }) => { onClick={handleClick} /> ); -}; +} diff --git a/src/renderer/components/metrics/ReactionsPill.tsx b/src/renderer/components/metrics/ReactionsPill.tsx index 1ca1c7859..2432e1156 100644 --- a/src/renderer/components/metrics/ReactionsPill.tsx +++ b/src/renderer/components/metrics/ReactionsPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { SmileyIcon } from '@primer/octicons-react'; import { IssueLabelToken, LabelGroup } from '@primer/react'; @@ -23,7 +21,7 @@ const reactionEmojiMap: Record = { HEART: '❤️', }; -export const ReactionsPill: FC = ({ reactionsCount, reactionGroups }) => { +export function ReactionsPill({ reactionsCount, reactionGroups }: ReactionsPillProps) { if (!reactionsCount) { return null; } @@ -58,4 +56,4 @@ export const ReactionsPill: FC = ({ reactionsCount, reaction metric={reactionsCount} /> ); -}; +} diff --git a/src/renderer/components/metrics/ReviewsPill.tsx b/src/renderer/components/metrics/ReviewsPill.tsx index fd153e4dc..3d9088a30 100644 --- a/src/renderer/components/metrics/ReviewsPill.tsx +++ b/src/renderer/components/metrics/ReviewsPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { CommentIcon } from '@primer/octicons-react'; import { type GitifyPullRequestReviewer, IconColor } from '../../types'; @@ -11,7 +9,7 @@ export interface ReviewsPillProps { reviewers: GitifyPullRequestReviewer[]; } -export const ReviewsPill: FC = ({ reviewers }) => { +export function ReviewsPill({ reviewers }: ReviewsPillProps) { if (!reviewers.length) { return null; } @@ -62,7 +60,7 @@ export const ReviewsPill: FC = ({ reviewers }) => { ) : null} ); -}; +} function getReviewGroups(reviewers: GitifyPullRequestReviewer[]): PullRequestReviewGroup[] { const groups = new Map, string[]>(); diff --git a/src/renderer/components/metrics/StackedPrsPill.tsx b/src/renderer/components/metrics/StackedPrsPill.tsx index db3970c49..e9065c4c2 100644 --- a/src/renderer/components/metrics/StackedPrsPill.tsx +++ b/src/renderer/components/metrics/StackedPrsPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { GitMergeIcon } from '@primer/octicons-react'; import { IconColor } from '../../types'; @@ -12,11 +10,7 @@ export interface StackedPrsPillProps { stackDepth?: number; } -export const StackedPrsPill: FC = ({ - isStacked, - stackPosition, - stackDepth, -}) => { +export function StackedPrsPill({ isStacked, stackPosition, stackDepth }: StackedPrsPillProps) { if (!isStacked) { return null; } @@ -32,4 +26,4 @@ export const StackedPrsPill: FC = ({ metric={metric} /> ); -}; +} diff --git a/src/renderer/components/metrics/SubIssueProgressPill.tsx b/src/renderer/components/metrics/SubIssueProgressPill.tsx index 5656335a7..c8c9990f3 100644 --- a/src/renderer/components/metrics/SubIssueProgressPill.tsx +++ b/src/renderer/components/metrics/SubIssueProgressPill.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { type GitifySubIssueProgress, IconColor } from '../../types'; import { MetricPill } from './MetricPill'; @@ -14,11 +12,11 @@ export interface SubIssueProgressWheelProps { size?: number; } -export const SubIssueProgressWheel: FC = ({ +export function SubIssueProgressWheel({ percent = 0, className, size = 12, -}) => { +}: SubIssueProgressWheelProps) { const radius = 6; const circumference = 2 * Math.PI * radius; const clampedPercent = Math.min(100, Math.max(0, percent)); @@ -59,9 +57,9 @@ export const SubIssueProgressWheel: FC = ({ )} ); -}; +} -export const SubIssueProgressPill: FC = ({ progress }) => { +export function SubIssueProgressPill({ progress }: SubIssueProgressPillProps) { if (!progress || progress.total === 0) { return null; } @@ -83,4 +81,4 @@ export const SubIssueProgressPill: FC = ({ progress } metric={`${progress.completed}/${progress.total}`} /> ); -}; +} diff --git a/src/renderer/components/notifications/AccountHeader.tsx b/src/renderer/components/notifications/AccountHeader.tsx index ff5ef936d..544c72d18 100644 --- a/src/renderer/components/notifications/AccountHeader.tsx +++ b/src/renderer/components/notifications/AccountHeader.tsx @@ -1,4 +1,4 @@ -import { type FC, type MouseEvent } from 'react'; +import { type MouseEvent } from 'react'; import { GitPullRequestIcon, IssueOpenedIcon } from '@primer/octicons-react'; import { Button, Stack } from '@primer/react'; @@ -23,13 +23,13 @@ export interface AccountHeaderProps { onToggle: () => void; } -export const AccountHeader: FC = ({ +export function AccountHeader({ account, error, notificationCount, isCollapsed, onToggle, -}) => { +}: AccountHeaderProps) { const Chevron = getChevronDetails(notificationCount > 0, !isCollapsed, 'account'); return ( @@ -89,4 +89,4 @@ export const AccountHeader: FC = ({ ); -}; +} diff --git a/src/renderer/components/notifications/NotificationFooter.tsx b/src/renderer/components/notifications/NotificationFooter.tsx index 21ec7b124..4b63df994 100644 --- a/src/renderer/components/notifications/NotificationFooter.tsx +++ b/src/renderer/components/notifications/NotificationFooter.tsx @@ -1,4 +1,4 @@ -import type { FC, MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { RelativeTime, Stack, Text } from '@primer/react'; @@ -15,9 +15,7 @@ export interface NotificationFooterProps { notification: GitifyNotification; } -export const NotificationFooter: FC = ({ - notification, -}: NotificationFooterProps) => { +export function NotificationFooter({ notification }: NotificationFooterProps) { const user = notification.subject.user; const userLabel = user ? getAccountAdapter(notification.account).formatNotificationUser(user) @@ -70,4 +68,4 @@ export const NotificationFooter: FC = ({ ); -}; +} diff --git a/src/renderer/components/notifications/NotificationHeader.tsx b/src/renderer/components/notifications/NotificationHeader.tsx index aeaedd95d..49b4cbfab 100644 --- a/src/renderer/components/notifications/NotificationHeader.tsx +++ b/src/renderer/components/notifications/NotificationHeader.tsx @@ -1,4 +1,4 @@ -import type { FC, MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { Stack } from '@primer/react'; @@ -16,9 +16,7 @@ export interface NotificationHeaderProps { notification: GitifyNotification; } -export const NotificationHeader: FC = ({ - notification, -}: NotificationHeaderProps) => { +export function NotificationHeader({ notification }: NotificationHeaderProps) { const showNumber = useSettingsStore((s) => s.showNumber); return ( @@ -51,4 +49,4 @@ export const NotificationHeader: FC = ({ ) ); -}; +} diff --git a/src/renderer/components/notifications/NotificationList.tsx b/src/renderer/components/notifications/NotificationList.tsx index fc4f41b8f..65413853b 100644 --- a/src/renderer/components/notifications/NotificationList.tsx +++ b/src/renderer/components/notifications/NotificationList.tsx @@ -1,4 +1,4 @@ -import { type FC, useCallback, useMemo, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { LegendList } from '@legendapp/list/react'; @@ -28,10 +28,10 @@ export interface NotificationListProps { * Flattened so one virtualizer windows across group boundaries, and so collapse * and exit-animation state survives rows unmounting on scroll. */ -export const NotificationList: FC = ({ +export function NotificationList({ accountNotifications, showAccountHeader, -}) => { +}: NotificationListProps) { const groupBy = useSettingsStore((s) => s.groupBy); const hasMultipleAccounts = useAccountsStore((s) => s.hasMultipleAccounts()); @@ -184,4 +184,4 @@ export const NotificationList: FC = ({ /> ); -}; +} diff --git a/src/renderer/components/notifications/NotificationRow.tsx b/src/renderer/components/notifications/NotificationRow.tsx index e77525f85..0edba702c 100644 --- a/src/renderer/components/notifications/NotificationRow.tsx +++ b/src/renderer/components/notifications/NotificationRow.tsx @@ -1,5 +1,3 @@ -import { type FC } from 'react'; - import { BellSlashIcon, CheckIcon, ReadIcon } from '@primer/octicons-react'; import { Stack, Text, Tooltip } from '@primer/react'; @@ -34,11 +32,11 @@ export interface NotificationRowProps { onAnimateExit: (animate: boolean) => void; } -export const NotificationRow: FC = ({ +export function NotificationRow({ notification, isAnimatingExit, onAnimateExit, -}: NotificationRowProps) => { +}: NotificationRowProps) { const { markNotificationsAsRead, markNotificationsAsDone, unsubscribeNotification } = useNotifications(); @@ -188,4 +186,4 @@ export const NotificationRow: FC = ({ )} ); -}; +} diff --git a/src/renderer/components/notifications/NotificationTitle.tsx b/src/renderer/components/notifications/NotificationTitle.tsx index 35f90559c..908c00fcb 100644 --- a/src/renderer/components/notifications/NotificationTitle.tsx +++ b/src/renderer/components/notifications/NotificationTitle.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { Text } from '@primer/react'; import { cn } from 'cn'; @@ -12,9 +10,7 @@ interface NotificationTitleProps { title: string; } -export const NotificationTitle: FC = ({ - title, -}: NotificationTitleProps) => { +export function NotificationTitle({ title }: NotificationTitleProps) { const wrapNotificationTitle = useSettingsStore((s) => s.wrapNotificationTitle); const parts = parseInlineCode(title); @@ -34,4 +30,4 @@ export const NotificationTitle: FC = ({ ))} ); -}; +} diff --git a/src/renderer/components/notifications/RepositoryHeader.tsx b/src/renderer/components/notifications/RepositoryHeader.tsx index 7327dab74..a7ecd3cfe 100644 --- a/src/renderer/components/notifications/RepositoryHeader.tsx +++ b/src/renderer/components/notifications/RepositoryHeader.tsx @@ -1,4 +1,4 @@ -import { type FC, type MouseEvent } from 'react'; +import { type MouseEvent } from 'react'; import { CheckIcon, ReadIcon } from '@primer/octicons-react'; import { Button, Stack } from '@primer/react'; @@ -27,14 +27,14 @@ export interface RepositoryHeaderProps { onAnimateExit: (animate: boolean) => void; } -export const RepositoryHeader: FC = ({ +export function RepositoryHeader({ repoName, repoNotifications, isCollapsed, isAnimatingExit, onToggle, onAnimateExit, -}) => { +}: RepositoryHeaderProps) { const { markNotificationsAsRead, markNotificationsAsDone } = useNotifications(); const shouldAnimateExit = shouldRemoveNotificationsFromState(); @@ -117,4 +117,4 @@ export const RepositoryHeader: FC = ({ )} ); -}; +} diff --git a/src/renderer/components/primitives/CustomCounter.tsx b/src/renderer/components/primitives/CustomCounter.tsx index 34a53630a..c2a7c8f60 100644 --- a/src/renderer/components/primitives/CustomCounter.tsx +++ b/src/renderer/components/primitives/CustomCounter.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { Text } from '@primer/react'; import { cn } from 'cn'; @@ -19,7 +17,7 @@ interface CustomCounterProps { * - would show screen vertical scrollbar which is undesirable. * - would not render '0' within a counter. */ -export const CustomCounter: FC = ({ value, scheme = 'secondary' }) => { +export function CustomCounter({ value, scheme = 'secondary' }: CustomCounterProps) { const baseStyles = 'px-2 py-0.25 rounded-full text-[10px] font-medium leading-none min-w-[16px] text-gitify-counter-text'; @@ -30,4 +28,4 @@ export const CustomCounter: FC = ({ value, scheme = 'seconda }; return {value}; -}; +} diff --git a/src/renderer/components/primitives/EmojiText.tsx b/src/renderer/components/primitives/EmojiText.tsx index 1618924cb..8f46d8a06 100644 --- a/src/renderer/components/primitives/EmojiText.tsx +++ b/src/renderer/components/primitives/EmojiText.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { convertTextToEmojiImgHtml } from '../../utils/ui/emojis'; @@ -6,7 +6,7 @@ export interface IEmojiText { text: string; } -export const EmojiText: FC = ({ text }) => { +export function EmojiText({ text }: IEmojiText) { const ref = useRef(null); const mountedRef = useRef(true); @@ -33,4 +33,4 @@ export const EmojiText: FC = ({ text }) => { }, [text]); return
; -}; +} diff --git a/src/renderer/components/primitives/Footer.tsx b/src/renderer/components/primitives/Footer.tsx index a60441fd0..3a3224df1 100644 --- a/src/renderer/components/primitives/Footer.tsx +++ b/src/renderer/components/primitives/Footer.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -11,7 +11,7 @@ interface FooterProps { * Footer component displays actions at the bottom of the page. * It is fixed to the viewport bottom. */ -export const Footer: FC = ({ children, justify }) => { +export function Footer({ children, justify }: FooterProps) { return (
@@ -19,4 +19,4 @@ export const Footer: FC = ({ children, justify }) => {
); -}; +} diff --git a/src/renderer/components/primitives/Header.tsx b/src/renderer/components/primitives/Header.tsx index 05aa53dde..63eebba2b 100644 --- a/src/renderer/components/primitives/Header.tsx +++ b/src/renderer/components/primitives/Header.tsx @@ -1,4 +1,3 @@ -import type { FC } from 'react'; import { useNavigate } from 'react-router-dom'; import { ArrowLeftIcon, type Icon } from '@primer/octicons-react'; @@ -14,7 +13,7 @@ interface HeaderProps { fetchOnBack?: boolean; } -export const Header: FC = (props: HeaderProps) => { +export function Header(props: HeaderProps) { const navigate = useNavigate(); const { refetchNotifications: fetchNotifications } = useNotifications(); @@ -42,4 +41,4 @@ export const Header: FC = (props: HeaderProps) => {
); -}; +} diff --git a/src/renderer/components/primitives/HoverButton.tsx b/src/renderer/components/primitives/HoverButton.tsx index bbc3f82a6..7b4b491ab 100644 --- a/src/renderer/components/primitives/HoverButton.tsx +++ b/src/renderer/components/primitives/HoverButton.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import type { Icon } from '@primer/octicons-react'; import { IconButton } from '@primer/react'; @@ -14,11 +12,7 @@ interface HoverButtonProps { variant?: VariantType; } -export const HoverButton: FC = ({ - enabled = true, - variant = 'invisible', - ...props -}: HoverButtonProps) => { +export function HoverButton({ enabled = true, variant = 'invisible', ...props }: HoverButtonProps) { return ( enabled && ( = ({ /> ) ); -}; +} diff --git a/src/renderer/components/primitives/HoverGroup.tsx b/src/renderer/components/primitives/HoverGroup.tsx index 4f6461466..e06edad8c 100644 --- a/src/renderer/components/primitives/HoverGroup.tsx +++ b/src/renderer/components/primitives/HoverGroup.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Stack } from '@primer/react'; @@ -28,11 +28,7 @@ interface HoverGroupProps { * title line or the issue number, and the footer reserves its width so the * pills wrap clear of the buttons. */ -export const HoverGroup: FC = ({ - bgColor, - children, - fullHeight = false, -}: HoverGroupProps) => { +export function HoverGroup({ bgColor, children, fullHeight = false }: HoverGroupProps) { return ( = ({ {children} ); -}; +} diff --git a/src/renderer/components/primitives/Title.tsx b/src/renderer/components/primitives/Title.tsx index f4709c015..360c77de4 100644 --- a/src/renderer/components/primitives/Title.tsx +++ b/src/renderer/components/primitives/Title.tsx @@ -1,4 +1,4 @@ -import type { FC, ReactNode } from 'react'; +import type { ReactNode } from 'react'; import type { Icon } from '@primer/octicons-react'; import { Heading, Stack } from '@primer/react'; @@ -12,7 +12,7 @@ interface TitleProps { tooltip?: ReactNode; } -export const Title: FC = ({ size: _size = 2, ...props }) => { +export function Title({ size: _size = 2, ...props }: TitleProps) { const name = props.children.toLowerCase().replaceAll(' ', '-'); return ( @@ -35,4 +35,4 @@ export const Title: FC = ({ size: _size = 2, ...props }) => { ); -}; +} diff --git a/src/renderer/components/settings/AppearanceSettings.tsx b/src/renderer/components/settings/AppearanceSettings.tsx index 20399fe54..f025c2261 100644 --- a/src/renderer/components/settings/AppearanceSettings.tsx +++ b/src/renderer/components/settings/AppearanceSettings.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { PaintbrushIcon, SyncIcon, ZoomInIcon, ZoomOutIcon } from '@primer/octicons-react'; import { Button, ButtonGroup, IconButton, Select, Stack, Text } from '@primer/react'; @@ -20,7 +18,7 @@ import { resetZoomLevel, } from '../../utils/ui/zoom'; -export const AppearanceSettings: FC = () => { +export function AppearanceSettings() { // Account store values const hasMultipleAccounts = useAccountsStore((s) => s.hasMultipleAccounts()); @@ -193,4 +191,4 @@ export const AppearanceSettings: FC = () => { ); -}; +} diff --git a/src/renderer/components/settings/NotificationSettings.tsx b/src/renderer/components/settings/NotificationSettings.tsx index d6ce79b6e..cd9618334 100644 --- a/src/renderer/components/settings/NotificationSettings.tsx +++ b/src/renderer/components/settings/NotificationSettings.tsx @@ -1,4 +1,4 @@ -import type { FC, MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { useNavigate } from 'react-router-dom'; import { @@ -37,7 +37,7 @@ import { GroupBy, Size } from '../../types'; import { hasAlternateScopes, hasRecommendedScopes } from '../../utils/auth/scopes'; import { openGitHubParticipatingDocs } from '../../utils/system/links'; -export const NotificationSettings: FC = () => { +export function NotificationSettings() { const navigate = useNavigate(); // Account store values @@ -418,4 +418,4 @@ export const NotificationSettings: FC = () => { ); -}; +} diff --git a/src/renderer/components/settings/SettingsFooter.tsx b/src/renderer/components/settings/SettingsFooter.tsx index 94bea2d85..86b7861cf 100644 --- a/src/renderer/components/settings/SettingsFooter.tsx +++ b/src/renderer/components/settings/SettingsFooter.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { PersonIcon, XCircleIcon } from '@primer/octicons-react'; import { Button, IconButton, Stack, Tooltip } from '@primer/react'; @@ -12,7 +12,7 @@ import { Footer } from '../primitives/Footer'; import { getAppVersion } from '../../utils/system/comms'; import { openGitifyReleaseNotes } from '../../utils/system/links'; -export const SettingsFooter: FC = () => { +export function SettingsFooter() { const [appVersion, setAppVersion] = useState(null); const { shortcuts } = useShortcutActions(); @@ -63,4 +63,4 @@ export const SettingsFooter: FC = () => { ); -}; +} diff --git a/src/renderer/components/settings/SettingsReset.tsx b/src/renderer/components/settings/SettingsReset.tsx index 3fe9d34dd..9a3989290 100644 --- a/src/renderer/components/settings/SettingsReset.tsx +++ b/src/renderer/components/settings/SettingsReset.tsx @@ -1,12 +1,10 @@ -import type { FC } from 'react'; - import { Button, Stack, useConfirm } from '@primer/react'; import { useSettingsStore } from '../../stores'; import { rendererLogInfo } from '../../utils/core/logger'; -export const SettingsReset: FC = () => { +export function SettingsReset() { const resetSettings = useSettingsStore((s) => s.reset); const confirm = useConfirm(); @@ -39,4 +37,4 @@ export const SettingsReset: FC = () => { ); -}; +} diff --git a/src/renderer/components/settings/SystemSettings.tsx b/src/renderer/components/settings/SystemSettings.tsx index 2702bbf9c..e6dcbe98a 100644 --- a/src/renderer/components/settings/SystemSettings.tsx +++ b/src/renderer/components/settings/SystemSettings.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { DeviceDesktopIcon, PencilIcon, SyncIcon } from '@primer/octicons-react'; import { Banner, Button, ButtonGroup, IconButton, Stack, Text } from '@primer/react'; @@ -34,7 +34,7 @@ import { const defaultSettings = DEFAULT_SETTINGS_STATE; -export const SystemSettings: FC = () => { +export function SystemSettings() { const shortcutRegistrationError = useShortcutRegistrationStore( (s) => s.shortcutRegistrationError, ); @@ -399,4 +399,4 @@ export const SystemSettings: FC = () => { ); -}; +} diff --git a/src/renderer/components/settings/TraySettings.tsx b/src/renderer/components/settings/TraySettings.tsx index f74065f63..abfa5c7c0 100644 --- a/src/renderer/components/settings/TraySettings.tsx +++ b/src/renderer/components/settings/TraySettings.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { DevicesIcon } from '@primer/octicons-react'; import { Stack, Text } from '@primer/react'; @@ -12,7 +10,7 @@ import { Checkbox } from '../fields/Checkbox'; import { RadioGroup } from '../fields/RadioGroup'; import { Title } from '../primitives/Title'; -export const TraySettings: FC = () => { +export function TraySettings() { const updateSetting = useSettingsStore((s) => s.updateSetting); // Setting store actions @@ -83,4 +81,4 @@ export const TraySettings: FC = () => { ); -}; +} diff --git a/src/renderer/icons/BitbucketIcon.tsx b/src/renderer/icons/BitbucketIcon.tsx index b1e749769..3793ab8dc 100644 --- a/src/renderer/icons/BitbucketIcon.tsx +++ b/src/renderer/icons/BitbucketIcon.tsx @@ -1,28 +1,28 @@ -import type { FC } from 'react'; - import type { OcticonProps } from '@primer/octicons-react'; /** * Bitbucket brand icon (black-and-white, uses currentColor). - * Implements FC so it is a drop-in for any place that expects an + * Takes OcticonProps so it is a drop-in for any place that expects an * octicon-shaped component. */ -export const BitbucketIcon: FC = ({ +export function BitbucketIcon({ size = 16, fill = 'currentColor', className, ...props -}) => ( - -); +}: OcticonProps) { + return ( + + ); +} diff --git a/src/renderer/icons/GitLabIcon.tsx b/src/renderer/icons/GitLabIcon.tsx index c81eee338..259c934f1 100644 --- a/src/renderer/icons/GitLabIcon.tsx +++ b/src/renderer/icons/GitLabIcon.tsx @@ -1,28 +1,28 @@ -import type { FC } from 'react'; - import type { OcticonProps } from '@primer/octicons-react'; /** * GitLab brand icon (black-and-white, uses currentColor). - * Implements FC so it is a drop-in for any place that expects an + * Takes OcticonProps so it is a drop-in for any place that expects an * octicon-shaped component. */ -export const GitLabIcon: FC = ({ +export function GitLabIcon({ size = 16, fill = 'currentColor', className, ...props -}) => ( - -); +}: OcticonProps) { + return ( + + ); +} diff --git a/src/renderer/icons/LogoIcon.tsx b/src/renderer/icons/LogoIcon.tsx index 9ccda8052..a1a043532 100644 --- a/src/renderer/icons/LogoIcon.tsx +++ b/src/renderer/icons/LogoIcon.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { cn } from 'cn'; import { APPLICATION } from '../../shared/constants'; @@ -18,48 +16,45 @@ const LIGHT_GRADIENT_END = '#FFFFFF'; const DARK_GRADIENT_START = '#22283B'; const DARK_GRADIENT_END = '#555B6E'; -export const LogoIcon: FC = ({ - isDark, - onClick, - size = Size.SMALL, - ...props -}: LogoIconProps) => ( - // oxlint-disable-next-line jsx-a11y/click-events-have-key-events -- Logo is purely decorative - -); + + ); +} diff --git a/src/renderer/icons/ScopeStatusIcon.tsx b/src/renderer/icons/ScopeStatusIcon.tsx index 22525782e..bfc9ff20c 100644 --- a/src/renderer/icons/ScopeStatusIcon.tsx +++ b/src/renderer/icons/ScopeStatusIcon.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { CheckCircleFillIcon, DashIcon, XCircleFillIcon } from '@primer/octicons-react'; export interface ScopeStatusIconProps { @@ -9,12 +7,12 @@ export interface ScopeStatusIconProps { withTestId?: boolean; } -export const ScopeStatusIcon: FC = ({ +export function ScopeStatusIcon({ granted, notApplicable = false, size = 14, withTestId = false, -}) => { +}: ScopeStatusIconProps) { if (notApplicable) { return ( = ({ size={size} /> ); -}; +} diff --git a/src/renderer/icons/VolumeDownIcon.tsx b/src/renderer/icons/VolumeDownIcon.tsx index b29824be1..cb5f7e59c 100644 --- a/src/renderer/icons/VolumeDownIcon.tsx +++ b/src/renderer/icons/VolumeDownIcon.tsx @@ -1,19 +1,19 @@ -import type { FC } from 'react'; - -export const VolumeDownIcon: FC = () => ( - -); +export function VolumeDownIcon() { + return ( + + ); +} diff --git a/src/renderer/icons/VolumeUpIcon.tsx b/src/renderer/icons/VolumeUpIcon.tsx index cfcffbffd..039ea8e22 100644 --- a/src/renderer/icons/VolumeUpIcon.tsx +++ b/src/renderer/icons/VolumeUpIcon.tsx @@ -1,17 +1,17 @@ -import type { FC } from 'react'; - -export const VolumeUpIcon: FC = () => ( - -); +export function VolumeUpIcon() { + return ( + + ); +} diff --git a/src/renderer/routes/AccountScopes.tsx b/src/renderer/routes/AccountScopes.tsx index 285c27476..a224a9ec4 100644 --- a/src/renderer/routes/AccountScopes.tsx +++ b/src/renderer/routes/AccountScopes.tsx @@ -1,4 +1,3 @@ -import type { FC } from 'react'; import { useLocation } from 'react-router-dom'; import { AlertFillIcon, LinkExternalIcon, ShieldCheckIcon } from '@primer/octicons-react'; @@ -27,7 +26,7 @@ interface LocationState { account: Account; } -export const AccountScopesRoute: FC = () => { +export function AccountScopesRoute() { const location = useLocation(); const { account } = location.state as LocationState; @@ -212,4 +211,4 @@ export const AccountScopesRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/Accounts.tsx b/src/renderer/routes/Accounts.tsx index 066af7164..f6c6a0e65 100644 --- a/src/renderer/routes/Accounts.tsx +++ b/src/renderer/routes/Accounts.tsx @@ -41,13 +41,13 @@ import { getAdapter, listAdapters } from '../utils/forges/registry'; import { openAccountProfile, openAccountSettings, openHost } from '../utils/system/links'; import { getPlatformIcon } from '../utils/ui/icons'; -const RecommendedScopesIcon: FC = ({ className, ...props }) => ( - -); +function RecommendedScopesIcon({ className, ...props }: OcticonProps) { + return ; +} -const AlternateScopesIcon: FC = ({ className, ...props }) => ( - -); +function AlternateScopesIcon({ className, ...props }: OcticonProps) { + return ; +} function getScopeIcon(account: Account): FC { if (hasRecommendedScopes(account)) { @@ -59,7 +59,7 @@ function getScopeIcon(account: Account): FC { return ShieldCheckIcon; } -export const AccountsRoute: FC = () => { +export function AccountsRoute() { const navigate = useNavigate(); const { logoutFromAccount } = useLogins(); @@ -407,4 +407,4 @@ export const AccountsRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/Filters.tsx b/src/renderer/routes/Filters.tsx index 7a7dca6ce..3172a8a17 100644 --- a/src/renderer/routes/Filters.tsx +++ b/src/renderer/routes/Filters.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { FilterIcon, FilterRemoveIcon } from '@primer/octicons-react'; import { Button, Stack, Tooltip } from '@primer/react'; @@ -17,7 +15,7 @@ import { Page } from '../components/layout/Page'; import { Footer } from '../components/primitives/Footer'; import { Header } from '../components/primitives/Header'; -export const FiltersRoute: FC = () => { +export function FiltersRoute() { const clearFilters = useFiltersStore((s) => s.reset); const hasMultipleAccounts = useAccountsStore((s) => s.hasMultipleAccounts()); @@ -53,4 +51,4 @@ export const FiltersRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/Login.tsx b/src/renderer/routes/Login.tsx index 525e5dab1..2e85a5f69 100644 --- a/src/renderer/routes/Login.tsx +++ b/src/renderer/routes/Login.tsx @@ -1,4 +1,4 @@ -import { type FC, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button, Heading, Stack, Text } from '@primer/react'; @@ -24,7 +24,7 @@ function pickPrimaryMethod(adapter: ForgeAdapter): LoginMethodDescriptor | undef return adapter.loginMethods.find((m) => m.variant === 'primary') ?? adapter.loginMethods[0]; } -export const LoginRoute: FC = () => { +export function LoginRoute() { const navigate = useNavigate(); const adapters = listAdapters(); @@ -208,4 +208,4 @@ export const LoginRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/Notifications.tsx b/src/renderer/routes/Notifications.tsx index 614df59d4..2e5d65196 100644 --- a/src/renderer/routes/Notifications.tsx +++ b/src/renderer/routes/Notifications.tsx @@ -1,4 +1,4 @@ -import { type FC, useMemo } from 'react'; +import { useMemo } from 'react'; import { useNotifications } from '../hooks/useNotifications'; import { useOnlineStatus } from '../hooks/useOnlineStatus'; @@ -13,7 +13,7 @@ import { getAccountUUID } from '../utils/auth/utils'; import { Errors } from '../utils/core/errors'; import { hasNoAccountErrors } from '../utils/notifications/status'; -export const NotificationsRoute: FC = () => { +export function NotificationsRoute() { const { notifications, status, globalError, hasNotifications } = useNotifications(); const isOnline = useOnlineStatus(); @@ -54,4 +54,4 @@ export const NotificationsRoute: FC = () => { /> ); -}; +} diff --git a/src/renderer/routes/Settings.tsx b/src/renderer/routes/Settings.tsx index 4a98bd4ba..a3bf61be0 100644 --- a/src/renderer/routes/Settings.tsx +++ b/src/renderer/routes/Settings.tsx @@ -1,5 +1,3 @@ -import type { FC } from 'react'; - import { GearIcon } from '@primer/octicons-react'; import { Stack } from '@primer/react'; @@ -13,7 +11,7 @@ import { SettingsReset } from '../components/settings/SettingsReset'; import { SystemSettings } from '../components/settings/SystemSettings'; import { TraySettings } from '../components/settings/TraySettings'; -export const SettingsRoute: FC = () => { +export function SettingsRoute() { return (
@@ -33,4 +31,4 @@ export const SettingsRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx b/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx index f3a1e3c0b..fa1e2a660 100644 --- a/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx +++ b/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx @@ -1,18 +1,18 @@ -import type { FC } from 'react'; - import { LoginWithPersonalAccessTokenForm } from '../../components/login/LoginWithPersonalAccessTokenForm'; -export const BitbucketLoginWithPersonalAccessTokenRoute: FC = () => ( - -); +export function BitbucketLoginWithPersonalAccessTokenRoute() { + return ( + + ); +} diff --git a/src/renderer/routes/gitea/LoginWithPersonalAccessToken.tsx b/src/renderer/routes/gitea/LoginWithPersonalAccessToken.tsx index 6a3291402..d806605b4 100644 --- a/src/renderer/routes/gitea/LoginWithPersonalAccessToken.tsx +++ b/src/renderer/routes/gitea/LoginWithPersonalAccessToken.tsx @@ -1,16 +1,16 @@ -import type { FC } from 'react'; - import { LoginWithPersonalAccessTokenForm } from '../../components/login/LoginWithPersonalAccessTokenForm'; -export const GiteaLoginWithPersonalAccessTokenRoute: FC = () => ( - -); +export function GiteaLoginWithPersonalAccessTokenRoute() { + return ( + + ); +} diff --git a/src/renderer/routes/github/LoginWithDeviceFlow.tsx b/src/renderer/routes/github/LoginWithDeviceFlow.tsx index 49b26f855..8c2e1dcbb 100644 --- a/src/renderer/routes/github/LoginWithDeviceFlow.tsx +++ b/src/renderer/routes/github/LoginWithDeviceFlow.tsx @@ -1,4 +1,4 @@ -import { type FC, type ReactNode, useCallback, useEffect, useState } from 'react'; +import { type ReactNode, useCallback, useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { @@ -34,7 +34,7 @@ interface LocationState { type ScopeChoice = 'public' | 'full'; -export const GitHubLoginWithDeviceFlowRoute: FC = () => { +export function GitHubLoginWithDeviceFlowRoute() { const navigate = useNavigate(); const location = useLocation(); const { account: reAuthAccount } = (location.state ?? {}) as LocationState; @@ -355,4 +355,4 @@ export const GitHubLoginWithDeviceFlowRoute: FC = () => { )} ); -}; +} diff --git a/src/renderer/routes/github/LoginWithGitHubCLI.tsx b/src/renderer/routes/github/LoginWithGitHubCLI.tsx index 84f7e35e6..e74b579af 100644 --- a/src/renderer/routes/github/LoginWithGitHubCLI.tsx +++ b/src/renderer/routes/github/LoginWithGitHubCLI.tsx @@ -1,4 +1,4 @@ -import { type FC, useCallback, useState } from 'react'; +import { useCallback, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { SignInIcon, TerminalIcon } from '@primer/octicons-react'; @@ -23,7 +23,7 @@ interface LocationState { account?: Account; } -export const GitHubLoginWithCLIRoute: FC = () => { +export function GitHubLoginWithCLIRoute() { const navigate = useNavigate(); const location = useLocation(); const { account: reAuthAccount } = (location.state ?? {}) as LocationState; @@ -115,4 +115,4 @@ export const GitHubLoginWithCLIRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/github/LoginWithOAuthApp.tsx b/src/renderer/routes/github/LoginWithOAuthApp.tsx index 969ebdd1d..aa6df4c7c 100644 --- a/src/renderer/routes/github/LoginWithOAuthApp.tsx +++ b/src/renderer/routes/github/LoginWithOAuthApp.tsx @@ -1,4 +1,4 @@ -import { type FC, useCallback, useState } from 'react'; +import { useCallback, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { BookIcon, EyeClosedIcon, EyeIcon, PersonIcon, SignInIcon } from '@primer/octicons-react'; @@ -28,7 +28,7 @@ interface LocationState { account?: Account; } -export const GitHubLoginWithOAuthAppRoute: FC = () => { +export function GitHubLoginWithOAuthAppRoute() { const navigate = useNavigate(); const location = useLocation(); const { account: reAuthAccount } = (location.state ?? {}) as LocationState; @@ -213,4 +213,4 @@ export const GitHubLoginWithOAuthAppRoute: FC = () => { ); -}; +} diff --git a/src/renderer/routes/github/LoginWithPersonalAccessToken.tsx b/src/renderer/routes/github/LoginWithPersonalAccessToken.tsx index 36c8c997e..b4b5ff44c 100644 --- a/src/renderer/routes/github/LoginWithPersonalAccessToken.tsx +++ b/src/renderer/routes/github/LoginWithPersonalAccessToken.tsx @@ -1,30 +1,30 @@ -import type { FC } from 'react'; - import { Text, Tooltip } from '@primer/react'; import { LoginWithPersonalAccessTokenForm } from '../../components/login/LoginWithPersonalAccessTokenForm'; import { formatRecommendedOAuthScopes } from '../../utils/auth/scopes'; -export const GitHubLoginWithPersonalAccessTokenRoute: FC = () => ( - - - The{' '} - - - {' '} - will be automatically selected for you. - - -); +export function GitHubLoginWithPersonalAccessTokenRoute() { + return ( + + + The{' '} + + + {' '} + will be automatically selected for you. + + + ); +} diff --git a/src/renderer/routes/gitlab/LoginWithPersonalAccessToken.tsx b/src/renderer/routes/gitlab/LoginWithPersonalAccessToken.tsx index dbe9bcf9b..ab329b1b6 100644 --- a/src/renderer/routes/gitlab/LoginWithPersonalAccessToken.tsx +++ b/src/renderer/routes/gitlab/LoginWithPersonalAccessToken.tsx @@ -1,24 +1,24 @@ -import type { FC } from 'react'; - import { Text } from '@primer/react'; import { LoginWithPersonalAccessTokenForm } from '../../components/login/LoginWithPersonalAccessTokenForm'; -export const GitLabLoginWithPersonalAccessTokenRoute: FC = () => ( - - - Requires the api scope, or a fine-grained token with{' '} - Todo (read, update) and{' '} - User (read) permissions. GitLab shows your To-Do items, - so you will see fewer notifications than on GitHub. - - -); +export function GitLabLoginWithPersonalAccessTokenRoute() { + return ( + + + Requires the api scope, or a fine-grained token with{' '} + Todo (read, update) and{' '} + User (read) permissions. GitLab shows your To-Do + items, so you will see fewer notifications than on GitHub. + + + ); +} diff --git a/vite.config.mts b/vite.config.mts index 9aaf77e5f..11ecf55ae 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -185,6 +185,13 @@ export default defineConfig({ 'default-param-last': 'error', 'default-case': 'error', curly: 'error', + 'react/function-component-definition': [ + 'error', + { + namedComponents: 'function-declaration', + unnamedComponents: 'arrow-function', + }, + ], 'react/exhaustive-deps': 'warn', 'react/rules-of-hooks': 'error', 'react/self-closing-comp': 'error',