Skip to content

Commit c0b7e3a

Browse files
Merge pull request #171 from DevLoversTeam/fix/qa-ui
(SP: 1) [Frontend] Fix UI Q&A spacing, accordion borders, and button backgrounds
2 parents f06afd9 + 8fc2036 commit c0b7e3a

7 files changed

Lines changed: 44 additions & 23 deletions

File tree

frontend/app/globals.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@
135135
}
136136
}
137137

138+
.qa-accordion-item:hover,
139+
.qa-accordion-item:focus-within,
140+
.qa-accordion-item[data-state='open'] {
141+
border-color: var(--qa-accent);
142+
}
143+
138144
.no-select {
139145
-webkit-user-select: none; /* Safari */
140146
-moz-user-select: none; /* Firefox */
@@ -244,4 +250,4 @@
244250
/* Зупинка при наведенні мишкою, щоб роздивитися */
245251
.hover\:pause:hover .animate-marquee-vertical {
246252
animation-play-state: paused;
247-
}
253+
}

frontend/components/header/MainSwitcher.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ function isBlogPath(pathname: string): boolean {
1414
return segments[0] === 'blog' || segments[1] === 'blog';
1515
}
1616

17+
function isQaPath(pathname: string): boolean {
18+
const segments = pathname.split('/').filter(Boolean);
19+
return segments[0] === 'q&a' || segments[1] === 'q&a';
20+
}
21+
1722
type MainSwitcherProps = {
1823
children: ReactNode;
1924
userExists: boolean;
@@ -28,6 +33,7 @@ export function MainSwitcher({
2833
blogCategories = [],
2934
}: MainSwitcherProps) {
3035
const pathname = usePathname();
36+
const isQa = isQaPath(pathname);
3137

3238
if (isShopPath(pathname)) return <>{children}</>;
3339

@@ -45,5 +51,9 @@ export function MainSwitcher({
4551
);
4652
}
4753

48-
return <main className="mx-auto px-6 min-h-[80vh]">{children}</main>;
54+
return (
55+
<main className={isQa ? 'mx-auto min-h-[80vh]' : 'mx-auto px-6 min-h-[80vh]'}>
56+
{children}
57+
</main>
58+
);
4959
}

frontend/components/q&a/AccordionList.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
'use client';
22

3-
import { ReactNode } from 'react';
3+
import type { CSSProperties, ReactNode } from 'react';
44
import {
55
Accordion,
66
AccordionItem,
77
AccordionTrigger,
88
AccordionContent,
99
} from '@/components/ui/accordion';
10+
import { qaTabStyles } from '@/data/qaTabs';
1011

1112
import CodeBlock from '@/components/q&a/CodeBlock';
1213
import type {
@@ -239,10 +240,23 @@ export default function AccordionList({ items }: { items: QuestionEntry[] }) {
239240
<Accordion type="single" collapsible className="w-full">
240241
{items.map((q, idx) => {
241242
const key = q.id ?? idx;
243+
const accent =
244+
qaTabStyles[q.category as keyof typeof qaTabStyles]?.accent;
242245
return (
243-
<AccordionItem key={key} value={String(key)}>
244-
<AccordionTrigger>{q.question}</AccordionTrigger>
245-
<AccordionContent>
246+
<AccordionItem
247+
key={key}
248+
value={String(key)}
249+
className="qa-accordion-item mb-3 last:mb-0 rounded-xl border border-black/5 bg-white/90 shadow-sm transition-colors last:border-b dark:border-white/10 dark:bg-neutral-900/80"
250+
style={
251+
accent
252+
? ({ '--qa-accent': accent } as CSSProperties)
253+
: undefined
254+
}
255+
>
256+
<AccordionTrigger className="px-4 hover:no-underline">
257+
{q.question}
258+
</AccordionTrigger>
259+
<AccordionContent className="px-4">
246260
<div className="space-y-3 pt-2">
247261
{q.answerBlocks.map((block, i) => renderBlock(block, i))}
248262
</div>

frontend/components/q&a/CodeBlock.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function CodeBlock({ code, language }: Props) {
1414
const { resolvedTheme } = useTheme();
1515
const [copied, setCopied] = useState(false);
1616

17-
const theme = resolvedTheme === 'dark' ? themes.nightOwl : themes.vsLight;
17+
const theme = resolvedTheme === 'dark' ? themes.nightOwl : themes.github;
1818

1919
const handleCopy = async () => {
2020
await navigator.clipboard.writeText(code);

frontend/components/q&a/Pagination.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export function Pagination({
9797
disabled={currentPage === 1}
9898
className={cn(
9999
'px-2 py-2 text-sm font-medium rounded-lg transition-colors sm:px-3',
100-
'border border-gray-300 dark:border-gray-700',
100+
'border border-gray-300 bg-white/90 dark:border-gray-700 dark:bg-neutral-900/80',
101101
currentPage === 1
102102
? 'text-gray-400 dark:text-gray-600 cursor-not-allowed'
103103
: 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]'
@@ -122,7 +122,7 @@ export function Pagination({
122122
onClick={() => onPageChange(page)}
123123
disabled={page === currentPage}
124124
className={cn(
125-
'min-w-[40px] px-3 py-2 text-sm font-medium rounded-lg transition-colors border border-transparent overflow-hidden',
125+
'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',
126126
page === currentPage
127127
? 'shadow-sm text-gray-700 dark:text-gray-300'
128128
: 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]'
@@ -150,7 +150,7 @@ export function Pagination({
150150
disabled={currentPage === totalPages}
151151
className={cn(
152152
'px-2 py-2 text-sm font-medium rounded-lg transition-colors sm:px-3',
153-
'border border-gray-300 dark:border-gray-700',
153+
'border border-gray-300 bg-white/90 dark:border-gray-700 dark:bg-neutral-900/80',
154154
currentPage === totalPages
155155
? 'text-gray-400 dark:text-gray-600 cursor-not-allowed'
156156
: 'text-gray-700 dark:text-gray-300 hover:bg-[var(--qa-accent-soft)]'

frontend/components/q&a/QaTabButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function QaTabButton({
2424
<TabsTrigger
2525
value={value}
2626
className={cn(
27-
'group relative h-full min-w-[96px] !flex !w-fit !flex-none !shrink-0 !items-center !justify-start gap-2 overflow-hidden rounded-xl border border-black/5 bg-transparent px-4 py-3 text-left text-xs font-semibold text-black shadow-sm transition-all duration-300 ease-out hover:-translate-y-0.5 hover:shadow-lg dark:border-white/20 dark:bg-transparent dark:text-white',
27+
'group relative h-full min-w-[96px] !flex !w-fit !flex-none !shrink-0 !items-center !justify-start gap-2 overflow-hidden rounded-xl border border-black/5 bg-white/90 px-4 py-3 text-left text-xs font-semibold text-black shadow-sm transition-all duration-300 ease-out hover:-translate-y-0.5 hover:shadow-lg dark:border-white/20 dark:bg-neutral-900/80 dark:text-white',
2828
'data-[state=active]:-translate-y-0.5 data-[state=active]:shadow-lg data-[state=active]:border-2 dark:data-[state=active]:border-2',
2929
style.color
3030
)}

frontend/components/q&a/useQaTabs.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use client';
22

33
import { useState, useEffect, useCallback } from 'react';
4-
import { useSearchParams, useParams } from 'next/navigation';
4+
import { useSearchParams } from 'next/navigation';
5+
import { useLocale } from 'next-intl';
56
import { useRouter } from '@/i18n/routing';
67
import { categoryData } from '@/data/category';
78
import {
8-
qaConstants,
99
type CategorySlug,
1010
type Locale,
1111
type PaginatedResponse,
@@ -15,11 +15,6 @@ import {
1515

1616
const CATEGORY_SLUGS = categoryData.map(category => category.slug);
1717
const DEFAULT_CATEGORY = CATEGORY_SLUGS[0] || 'html';
18-
function resolveLocale(value: string): Locale {
19-
return qaConstants.supportedLocales.includes(value as Locale)
20-
? (value as Locale)
21-
: 'en';
22-
}
2318

2419
function isCategorySlug(value: string): value is CategorySlug {
2520
return CATEGORY_SLUGS.includes(value);
@@ -28,11 +23,7 @@ function isCategorySlug(value: string): value is CategorySlug {
2823
export function useQaTabs() {
2924
const router = useRouter();
3025
const searchParams = useSearchParams();
31-
const params = useParams();
32-
33-
const locale =
34-
typeof params.locale === 'string' ? params.locale : params.locale?.[0] ?? '';
35-
const localeKey = resolveLocale(locale);
26+
const localeKey = useLocale() as Locale;
3627

3728
const rawPage = searchParams.get('page');
3829
const pageFromUrl = rawPage ? Number(rawPage) : 1;

0 commit comments

Comments
 (0)