From e16b88ba7e2930f8ad03e35383ab1f554336f61b Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Sat, 23 May 2026 13:14:06 +0300 Subject: [PATCH] chore: remove outdated code --- src/widgets/Navigation/index.ts | 4 - src/widgets/Navigation/model/types.ts | 14 --- .../Navigation/ui/MobileNav.stories.tsx | 28 ------ src/widgets/Navigation/ui/MobileNav.test.tsx | 62 ------------- src/widgets/Navigation/ui/MobileNav.tsx | 63 -------------- .../Navigation/ui/SidebarNav.stories.tsx | 29 ------- src/widgets/Navigation/ui/SidebarNav.test.tsx | 84 ------------------ src/widgets/Navigation/ui/SidebarNav.tsx | 87 ------------------- .../Navigation/ui/UtilityBar.stories.tsx | 20 ----- src/widgets/Navigation/ui/UtilityBar.test.tsx | 29 ------- src/widgets/Navigation/ui/UtilityBar.tsx | 32 ------- src/widgets/index.ts | 1 - 12 files changed, 453 deletions(-) delete mode 100644 src/widgets/Navigation/index.ts delete mode 100644 src/widgets/Navigation/model/types.ts delete mode 100644 src/widgets/Navigation/ui/MobileNav.stories.tsx delete mode 100644 src/widgets/Navigation/ui/MobileNav.test.tsx delete mode 100644 src/widgets/Navigation/ui/MobileNav.tsx delete mode 100644 src/widgets/Navigation/ui/SidebarNav.stories.tsx delete mode 100644 src/widgets/Navigation/ui/SidebarNav.test.tsx delete mode 100644 src/widgets/Navigation/ui/SidebarNav.tsx delete mode 100644 src/widgets/Navigation/ui/UtilityBar.stories.tsx delete mode 100644 src/widgets/Navigation/ui/UtilityBar.test.tsx delete mode 100644 src/widgets/Navigation/ui/UtilityBar.tsx diff --git a/src/widgets/Navigation/index.ts b/src/widgets/Navigation/index.ts deleted file mode 100644 index d7cb7c5..0000000 --- a/src/widgets/Navigation/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { NavItem } from './model/types'; -export { MobileNav } from './ui/MobileNav'; -export { SidebarNav } from './ui/SidebarNav'; -export { UtilityBar } from './ui/UtilityBar'; diff --git a/src/widgets/Navigation/model/types.ts b/src/widgets/Navigation/model/types.ts deleted file mode 100644 index c8e0334..0000000 --- a/src/widgets/Navigation/model/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type NavItem = { - /** - * Section HTML id for anchor scrolling - */ - id: string; - /** - * Display label - */ - label: string; - /** - * Display number prefix (e.g. "01") - */ - number: string; -}; diff --git a/src/widgets/Navigation/ui/MobileNav.stories.tsx b/src/widgets/Navigation/ui/MobileNav.stories.tsx deleted file mode 100644 index 8b44421..0000000 --- a/src/widgets/Navigation/ui/MobileNav.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/nextjs-vite'; -import { MobileNav } from './MobileNav'; - -// MobileNav is lg:hidden — it renders only on mobile viewports. -// Use the viewport toolbar in Storybook to switch to a mobile size to see it. -const meta: Meta = { - title: 'Widgets/MobileNav', - component: MobileNav, - parameters: { - viewport: { - defaultViewport: 'mobile1', - }, - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - args: { - items: [ - { id: 'bio', label: 'Bio', number: '01' }, - { id: 'work', label: 'Work', number: '02' }, - { id: 'contact', label: 'Contact', number: '03' }, - ], - }, -}; diff --git a/src/widgets/Navigation/ui/MobileNav.test.tsx b/src/widgets/Navigation/ui/MobileNav.test.tsx deleted file mode 100644 index 3d4036a..0000000 --- a/src/widgets/Navigation/ui/MobileNav.test.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import type { NavItem } from '../model/types'; -import { MobileNav } from './MobileNav'; - -vi.mock('next/navigation', () => ({ usePathname: vi.fn(() => '/') })); - -const ITEMS: NavItem[] = [ - { id: 'intro', label: 'Intro', number: '01' }, - { id: 'bio', label: 'Bio', number: '02' }, -]; - -describe('MobileNav', () => { - describe('rendering', () => { - it('renders title "allmy.work"', () => { - render(); - expect(screen.getByText('allmy.work')).toBeInTheDocument(); - }); - - it('renders toggle button with text "Menu" initially', () => { - render(); - expect(screen.getByRole('button', { name: 'Menu' })).toBeInTheDocument(); - }); - - it('menu items are hidden initially', () => { - render(); - expect(screen.queryByRole('link', { name: /intro/i })).not.toBeInTheDocument(); - }); - }); - - describe('navigation items', () => { - it('shows items as links with correct hrefs when open', async () => { - render(); - await userEvent.click(screen.getByRole('button', { name: 'Menu' })); - expect(screen.getByRole('link', { name: /01.*Intro/i })).toHaveAttribute('href', '/intro'); - expect(screen.getByRole('link', { name: /02.*Bio/i })).toHaveAttribute('href', '/bio'); - }); - }); - - describe('interactions', () => { - it('click toggle shows links and changes label to "Close"', async () => { - render(); - await userEvent.click(screen.getByRole('button', { name: 'Menu' })); - expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); - expect(screen.getByText('Intro')).toBeInTheDocument(); - }); - - it('closes menu when pathname changes', async () => { - const { usePathname } = await import('next/navigation'); - vi.mocked(usePathname).mockReturnValue('/'); - const { rerender } = render(); - await userEvent.click(screen.getByRole('button', { name: 'Menu' })); - expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); - - vi.mocked(usePathname).mockReturnValue('/bio'); - rerender(); - - expect(screen.getByRole('button', { name: 'Menu' })).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument(); - }); - }); -}); diff --git a/src/widgets/Navigation/ui/MobileNav.tsx b/src/widgets/Navigation/ui/MobileNav.tsx deleted file mode 100644 index ea4e808..0000000 --- a/src/widgets/Navigation/ui/MobileNav.tsx +++ /dev/null @@ -1,63 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { usePathname } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { cn } from '$shared/lib'; -import type { NavItem } from '../model/types'; - -/** - * Props for MobileNav. - */ -interface Props { - /** - * Navigation items to render - */ - items: NavItem[]; -} - -/** - * Mobile navigation overlay, hidden on lg+ screens. - * Closes automatically when the URL pathname changes after navigation. - */ -export function MobileNav({ items }: Props) { - const [isOpen, setIsOpen] = useState(false); - const pathname = usePathname(); - - // biome-ignore lint/correctness/useExhaustiveDependencies: pathname is the trigger, not a value used inside the callback - useEffect(() => { - setIsOpen(false); - }, [pathname]); - - return ( -
-
-

allmy.work

- -
- {isOpen && ( -
- {items.map((item) => ( - -
- {item.number} - - {item.label} - -
- - ))} -
- )} -
- ); -} diff --git a/src/widgets/Navigation/ui/SidebarNav.stories.tsx b/src/widgets/Navigation/ui/SidebarNav.stories.tsx deleted file mode 100644 index 2c98381..0000000 --- a/src/widgets/Navigation/ui/SidebarNav.stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/nextjs-vite'; -import { SidebarNav } from './SidebarNav'; - -// SidebarNav is hidden lg:block — it renders only on desktop viewports. -// Use the viewport toolbar in Storybook to switch to a desktop size to see it. -const meta: Meta = { - title: 'Widgets/SidebarNav', - component: SidebarNav, - parameters: { - layout: 'fullscreen', - viewport: { - defaultViewport: 'desktop', - }, - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - args: { - items: [ - { id: 'bio', label: 'Bio', number: '01' }, - { id: 'work', label: 'Work', number: '02' }, - { id: 'contact', label: 'Contact', number: '03' }, - ], - }, -}; diff --git a/src/widgets/Navigation/ui/SidebarNav.test.tsx b/src/widgets/Navigation/ui/SidebarNav.test.tsx deleted file mode 100644 index 10d16f3..0000000 --- a/src/widgets/Navigation/ui/SidebarNav.test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import type { NavItem } from '../model/types'; -import { SidebarNav } from './SidebarNav'; - -vi.mock('next/navigation', () => ({ - usePathname: vi.fn(), -})); - -import { usePathname } from 'next/navigation'; - -const ITEMS: NavItem[] = [ - { id: 'bio', label: 'Bio', number: '01' }, - { id: 'work', label: 'Work', number: '02' }, -]; - -describe('SidebarNav', () => { - describe('rendering', () => { - beforeEach(() => { - vi.mocked(usePathname).mockReturnValue('/bio'); - }); - - it('renders a nav element', () => { - render(); - expect(screen.getByRole('navigation')).toBeInTheDocument(); - }); - - it('renders "Index" heading', () => { - render(); - expect(screen.getByText('Index')).toBeInTheDocument(); - }); - - it('renders "Digital Monograph" subtitle', () => { - render(); - expect(screen.getByText('Digital Monograph')).toBeInTheDocument(); - }); - - it('renders each item label and number', () => { - render(); - expect(screen.getByText('Bio')).toBeInTheDocument(); - expect(screen.getByText('01')).toBeInTheDocument(); - expect(screen.getByText('Work')).toBeInTheDocument(); - expect(screen.getByText('02')).toBeInTheDocument(); - }); - - it('renders "Quick Links" section', () => { - render(); - expect(screen.getByText('Quick Links')).toBeInTheDocument(); - }); - - it('renders Email quick link', () => { - render(); - expect(screen.getByRole('link', { name: 'Email' })).toBeInTheDocument(); - }); - - it('renders a link for each nav item', () => { - render(); - expect(screen.getByRole('link', { name: /Bio/i })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: /Work/i })).toBeInTheDocument(); - }); - }); - - describe('active state', () => { - it('marks matching pathname item as active (no opacity-40)', () => { - vi.mocked(usePathname).mockReturnValue('/bio'); - render(); - const activeLink = screen.getByRole('link', { name: /Bio/i }); - expect(activeLink).not.toHaveClass('opacity-40'); - }); - - it('marks non-matching item as inactive (opacity-40)', () => { - vi.mocked(usePathname).mockReturnValue('/bio'); - render(); - const inactiveLink = screen.getByRole('link', { name: /Work/i }); - expect(inactiveLink).toHaveClass('opacity-40'); - }); - - it('marks first item active at root path', () => { - vi.mocked(usePathname).mockReturnValue('/'); - render(); - const firstLink = screen.getByRole('link', { name: /Bio/i }); - expect(firstLink).not.toHaveClass('opacity-40'); - }); - }); -}); diff --git a/src/widgets/Navigation/ui/SidebarNav.tsx b/src/widgets/Navigation/ui/SidebarNav.tsx deleted file mode 100644 index d48543d..0000000 --- a/src/widgets/Navigation/ui/SidebarNav.tsx +++ /dev/null @@ -1,87 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { usePathname } from 'next/navigation'; -import { CONTACT_LINKS, cn } from '$shared/lib'; -import type { NavItem } from '../model/types'; - -/** - * Props for SidebarNav. - */ -interface Props { - /** - * Navigation items to render - */ - items: NavItem[]; -} - -/** - * Fixed sidebar navigation, visible on lg+ screens. - * Active section determined by current URL pathname. - */ -export function SidebarNav({ items }: Props) { - const pathname = usePathname(); - - /** - * An item is active when its slug matches the current pathname, - * or when the pathname is root and it is the first item. - */ - function isActive(item: NavItem): boolean { - if (pathname === `/${item.id}`) { - return true; - } - if (pathname === '/' && items[0]?.id === item.id) { - return true; - } - return false; - } - - return ( - - ); -} diff --git a/src/widgets/Navigation/ui/UtilityBar.stories.tsx b/src/widgets/Navigation/ui/UtilityBar.stories.tsx deleted file mode 100644 index df7cf2b..0000000 --- a/src/widgets/Navigation/ui/UtilityBar.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/nextjs-vite'; -import { UtilityBar } from './UtilityBar'; - -const meta: Meta = { - title: 'Widgets/UtilityBar', - component: UtilityBar, - decorators: [ - (Story) => ( -
- -
- ), - ], -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/src/widgets/Navigation/ui/UtilityBar.test.tsx b/src/widgets/Navigation/ui/UtilityBar.test.tsx deleted file mode 100644 index d2d0ecf..0000000 --- a/src/widgets/Navigation/ui/UtilityBar.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { UtilityBar } from './UtilityBar'; - -describe('UtilityBar', () => { - describe('rendering', () => { - it('renders "Contact" label', () => { - render(); - expect(screen.getByText('Contact')).toBeInTheDocument(); - }); - - it('renders email link with correct href', () => { - render(); - const link = screen.getByRole('link', { name: 'hello@allmy.work' }); - expect(link).toBeInTheDocument(); - expect(link).toHaveAttribute('href', 'mailto:hello@allmy.work'); - }); - - it('renders "Download CV" button', () => { - render(); - expect(screen.getByRole('button', { name: /download cv/i })).toBeInTheDocument(); - }); - - it('Download CV button has primary variant class', () => { - render(); - const btn = screen.getByRole('button', { name: /download cv/i }); - expect(btn).toHaveClass('bg-blue'); - }); - }); -}); diff --git a/src/widgets/Navigation/ui/UtilityBar.tsx b/src/widgets/Navigation/ui/UtilityBar.tsx deleted file mode 100644 index 3e93030..0000000 --- a/src/widgets/Navigation/ui/UtilityBar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client'; - -import { CONTACT_LINKS } from '$shared/lib'; -import { Button } from '$shared/ui'; - -/** - * Fixed bottom utility bar with contact info and CV download. - */ -export function UtilityBar() { - /** - * Handles CV download action. - */ - function handleDownloadCV() { - console.log('Downloading CV...'); - } - - return ( -
-
- - -
-
- ); -} diff --git a/src/widgets/index.ts b/src/widgets/index.ts index 71ffc2e..ddcc5a9 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -1,2 +1 @@ export * from './Footer'; -export * from './Navigation';