diff --git a/frontend/app/globals.css b/frontend/app/globals.css index d819bc31..c8da09dc 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -135,6 +135,12 @@ } } +.qa-accordion-item:hover, +.qa-accordion-item:focus-within, +.qa-accordion-item[data-state='open'] { + border-color: var(--qa-accent); +} + .no-select { -webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */ @@ -244,4 +250,4 @@ /* Зупинка при наведенні мишкою, щоб роздивитися */ .hover\:pause:hover .animate-marquee-vertical { animation-play-state: paused; -} \ No newline at end of file +} diff --git a/frontend/components/header/MainSwitcher.tsx b/frontend/components/header/MainSwitcher.tsx index fe5dd834..0bdd0df4 100644 --- a/frontend/components/header/MainSwitcher.tsx +++ b/frontend/components/header/MainSwitcher.tsx @@ -14,6 +14,11 @@ function isBlogPath(pathname: string): boolean { return segments[0] === 'blog' || segments[1] === 'blog'; } +function isQaPath(pathname: string): boolean { + const segments = pathname.split('/').filter(Boolean); + return segments[0] === 'q&a' || segments[1] === 'q&a'; +} + type MainSwitcherProps = { children: ReactNode; userExists: boolean; @@ -28,6 +33,7 @@ export function MainSwitcher({ blogCategories = [], }: MainSwitcherProps) { const pathname = usePathname(); + const isQa = isQaPath(pathname); if (isShopPath(pathname)) return <>{children}; @@ -45,5 +51,9 @@ export function MainSwitcher({ ); } - return
{children}
; + return ( +
+ {children} +
+ ); } diff --git a/frontend/components/q&a/AccordionList.tsx b/frontend/components/q&a/AccordionList.tsx index b1538f06..890e1411 100644 --- a/frontend/components/q&a/AccordionList.tsx +++ b/frontend/components/q&a/AccordionList.tsx @@ -1,12 +1,13 @@ 'use client'; -import { ReactNode } from 'react'; +import type { CSSProperties, ReactNode } from 'react'; import { Accordion, AccordionItem, AccordionTrigger, AccordionContent, } from '@/components/ui/accordion'; +import { qaTabStyles } from '@/data/qaTabs'; import CodeBlock from '@/components/q&a/CodeBlock'; import type { @@ -239,10 +240,23 @@ export default function AccordionList({ items }: { items: QuestionEntry[] }) { {items.map((q, idx) => { const key = q.id ?? idx; + const accent = + qaTabStyles[q.category as keyof typeof qaTabStyles]?.accent; return ( - - {q.question} - + + + {q.question} + +
{q.answerBlocks.map((block, i) => renderBlock(block, i))}
diff --git a/frontend/components/q&a/CodeBlock.tsx b/frontend/components/q&a/CodeBlock.tsx index 86b7471a..9c765b1d 100644 --- a/frontend/components/q&a/CodeBlock.tsx +++ b/frontend/components/q&a/CodeBlock.tsx @@ -14,7 +14,7 @@ export default function CodeBlock({ code, language }: Props) { const { resolvedTheme } = useTheme(); const [copied, setCopied] = useState(false); - const theme = resolvedTheme === 'dark' ? themes.nightOwl : themes.vsLight; + const theme = resolvedTheme === 'dark' ? themes.nightOwl : themes.github; const handleCopy = async () => { await navigator.clipboard.writeText(code); diff --git a/frontend/components/q&a/Pagination.tsx b/frontend/components/q&a/Pagination.tsx index 5e275680..6487d9a7 100644 --- a/frontend/components/q&a/Pagination.tsx +++ b/frontend/components/q&a/Pagination.tsx @@ -97,7 +97,7 @@ export function Pagination({ disabled={currentPage === 1} className={cn( 'px-2 py-2 text-sm font-medium rounded-lg transition-colors sm:px-3', - 'border border-gray-300 dark:border-gray-700', + 'border border-gray-300 bg-white/90 dark:border-gray-700 dark:bg-neutral-900/80', currentPage === 1 ? 'text-gray-400 dark:text-gray-600 cursor-not-allowed' : 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]' @@ -122,7 +122,7 @@ export function Pagination({ onClick={() => onPageChange(page)} disabled={page === currentPage} className={cn( - 'min-w-[40px] px-3 py-2 text-sm font-medium rounded-lg transition-colors border border-transparent overflow-hidden', + 'min-w-[40px] px-3 py-2 text-sm font-medium rounded-lg transition-colors border border-transparent overflow-hidden bg-white/90 dark:bg-neutral-900/80', page === currentPage ? 'shadow-sm text-gray-700 dark:text-gray-300' : 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]' @@ -150,7 +150,7 @@ export function Pagination({ disabled={currentPage === totalPages} className={cn( 'px-2 py-2 text-sm font-medium rounded-lg transition-colors sm:px-3', - 'border border-gray-300 dark:border-gray-700', + 'border border-gray-300 bg-white/90 dark:border-gray-700 dark:bg-neutral-900/80', currentPage === totalPages ? 'text-gray-400 dark:text-gray-600 cursor-not-allowed' : 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]' diff --git a/frontend/components/q&a/QaTabButton.tsx b/frontend/components/q&a/QaTabButton.tsx index b183afd1..9bfe1c47 100644 --- a/frontend/components/q&a/QaTabButton.tsx +++ b/frontend/components/q&a/QaTabButton.tsx @@ -24,7 +24,7 @@ export function QaTabButton({ category.slug); const DEFAULT_CATEGORY = CATEGORY_SLUGS[0] || 'html'; -function resolveLocale(value: string): Locale { - return qaConstants.supportedLocales.includes(value as Locale) - ? (value as Locale) - : 'en'; -} function isCategorySlug(value: string): value is CategorySlug { return CATEGORY_SLUGS.includes(value); @@ -28,11 +23,7 @@ function isCategorySlug(value: string): value is CategorySlug { export function useQaTabs() { const router = useRouter(); const searchParams = useSearchParams(); - const params = useParams(); - - const locale = - typeof params.locale === 'string' ? params.locale : params.locale?.[0] ?? ''; - const localeKey = resolveLocale(locale); + const localeKey = useLocale() as Locale; const rawPage = searchParams.get('page'); const pageFromUrl = rawPage ? Number(rawPage) : 1;