From 6d66e212621be9a036f623460b75fee914ce7bff Mon Sep 17 00:00:00 2001 From: Oleg Schurov Date: Tue, 8 Jul 2025 16:38:08 +0300 Subject: [PATCH] completed tasks to optimization browse page --- src/components/QuestionItem/question-item.tsx | 126 +++++++------ src/components/QuestionList/question-list.tsx | 29 ++- src/components/ThemeToggle/theme-toggle.tsx | 63 ++++--- src/data/questions/frontend/htmlCollection.ts | 177 ++++++++---------- 4 files changed, 194 insertions(+), 201 deletions(-) diff --git a/src/components/QuestionItem/question-item.tsx b/src/components/QuestionItem/question-item.tsx index 9fc846c..07d3b02 100644 --- a/src/components/QuestionItem/question-item.tsx +++ b/src/components/QuestionItem/question-item.tsx @@ -5,7 +5,7 @@ import { QuestionItemSummaryButton } from "@/components/QuestionItem/question-it import summaryStore from "@/stores/summaryStore.ts"; import type { Question } from "@/types/question.types.ts"; import { useStore } from "@nanostores/react"; -import { type MouseEventHandler, useCallback, useState } from "react"; +import { memo, type MouseEventHandler, useCallback, useState } from "react"; import { Card } from "@/components/ui"; import { clsx } from "clsx"; @@ -14,68 +14,70 @@ interface QuestionItemProperties extends Question { noSummary?: boolean; } -export const QuestionItem = ({ - className, - name, - tags, - answer, - references, - slug, - similars, - noSummary, -}: QuestionItemProperties) => { - const [isExpanded, setIsExpanded] = useState(false); +export const QuestionItem = memo( + ({ + className, + name, + tags, + answer, + references, + slug, + similars, + noSummary, + }: QuestionItemProperties) => { + const [isExpanded, setIsExpanded] = useState(false); - const summary = useStore(summaryStore.state); - const isQuestionInSummary = - summary.questions.findIndex((question) => question.slug === slug) !== -1; + const summary = useStore(summaryStore.state); + const isQuestionInSummary = + summary.questions.findIndex((question) => question.slug === slug) !== -1; - const onSummaryButtonClick = useCallback< - MouseEventHandler - >((event) => { - event.stopPropagation(); + const onSummaryButtonClick = useCallback< + MouseEventHandler + >((event) => { + event.stopPropagation(); - summaryStore.questions.toggle({ - slug, - tags, - answer, - name, - references, - similars, - }); - }, []); + summaryStore.questions.toggle({ + slug, + tags, + answer, + name, + references, + similars, + }); + }, []); - // QuestionItem className={clsx(styles.questionItem, {[styles.questionItem_active]: isQuestionInSummary, [styles.questionItem_summary]: !noSummary}, className)} - return ( -
setIsExpanded(!isExpanded)} - > - {!noSummary && ( - - )} - - - {isExpanded && } - - -
- ); -}; + // QuestionItem className={clsx(styles.questionItem, {[styles.questionItem_active]: isQuestionInSummary, [styles.questionItem_summary]: !noSummary}, className)} + return ( +
setIsExpanded(!isExpanded)} + > + {!noSummary && ( + + )} + + + {isExpanded && } + + +
+ ); + }, +); diff --git a/src/components/QuestionList/question-list.tsx b/src/components/QuestionList/question-list.tsx index f0cebb2..0edbe67 100644 --- a/src/components/QuestionList/question-list.tsx +++ b/src/components/QuestionList/question-list.tsx @@ -1,6 +1,7 @@ import { QuestionItem } from "@/components/QuestionItem"; import type { Question } from "@/types/question.types.ts"; import { clsx } from "clsx"; +import { memo } from "react"; interface QuestionListProperties { list: Question[]; @@ -8,18 +9,16 @@ interface QuestionListProperties { className?: string | string[]; } -export const QuestionList = ({ - className, - list, - noSummary, -}: QuestionListProperties) => { - return ( -
    - {list.map((item) => ( -
  • - -
  • - ))} -
- ); -}; +export const QuestionList = memo( + ({ className, list, noSummary }: QuestionListProperties) => { + return ( +
    + {list.map((item) => ( +
  • + +
  • + ))} +
+ ); + }, +); diff --git a/src/components/ThemeToggle/theme-toggle.tsx b/src/components/ThemeToggle/theme-toggle.tsx index c6c0594..1052bd7 100644 --- a/src/components/ThemeToggle/theme-toggle.tsx +++ b/src/components/ThemeToggle/theme-toggle.tsx @@ -1,25 +1,36 @@ -import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui"; +import { + Button, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui"; import { capitalize } from "@/utils/capitalize.ts"; import { loadIcons } from "@iconify-icon/react"; import { Icon } from "@iconify-icon/react/dist/iconify.js"; import { useEffect, useState } from "react"; -loadIcons(['gravity-ui:moon', 'gravity-ui:sun', 'gravity-ui:display']) +loadIcons(["gravity-ui:moon", "gravity-ui:sun", "gravity-ui:display"]); -type Theme = 'light' | 'dark' | 'system'; +type Theme = "light" | "dark" | "system"; export const ThemeToggle = () => { - const [theme, setTheme] = useState('system'); + const [theme, setTheme] = useState("system"); - const icon = theme === 'light' ? 'gravity-ui:sun' : (theme === 'dark' ? 'gravity-ui:moon' : 'gravity-ui:display'); + const icon = + theme === "light" + ? "gravity-ui:sun" + : theme === "dark" + ? "gravity-ui:moon" + : "gravity-ui:display"; const toggleTheme = () => { - if (theme === 'system') { - setTheme('dark') - } else if (theme === 'dark') { - setTheme('light') + if (theme === "system") { + setTheme("dark"); + } else if (theme === "dark") { + setTheme("light"); } else { - setTheme('system') + setTheme("system"); } }; @@ -27,34 +38,34 @@ export const ThemeToggle = () => { let finalTheme: Exclude; switch (theme) { - case 'system': { - finalTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; - break + case "system": { + finalTheme = window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + break; } case "dark": { - finalTheme = 'dark'; - break + finalTheme = "dark"; + break; } case "light": { - finalTheme = 'light'; + finalTheme = "light"; } } - if (finalTheme === 'dark') { - document.documentElement.classList.add('dark'); + if (finalTheme === "dark") { + document.documentElement.classList.add("dark"); } else { - document.documentElement.classList.remove('dark'); + document.documentElement.classList.remove("dark"); } - }, [theme]); + }, [theme]); return ( - + @@ -62,5 +73,5 @@ export const ThemeToggle = () => { - ) -} + ); +}; diff --git a/src/data/questions/frontend/htmlCollection.ts b/src/data/questions/frontend/htmlCollection.ts index 36f04a2..be260be 100644 --- a/src/data/questions/frontend/htmlCollection.ts +++ b/src/data/questions/frontend/htmlCollection.ts @@ -1,173 +1,154 @@ import tags from "@/data/tags"; -import type {QuestionSection} from "@/types/question.types.ts"; -import {createQuestionSlug} from "@/utils/slug.ts"; +import type { QuestionSection } from "@/types/question.types.ts"; +import { createQuestionSlug } from "@/utils/slug.ts"; -const slug = createQuestionSlug('html'); +const slug = createQuestionSlug("html"); export const slugs = { - semantic: slug('semantic'), - "block-line": slug('block-line'), - "alt-required": slug('alt-required'), - "alt-empty": slug('alt-empty'), - "web-components": slug('web-components'), - "shadow-dom": slug('shadow-dom'), - "custom-elements": slug('custom-elements'), - "web-manifest": slug('web-manifest'), + semantic: slug("semantic"), + "block-line": slug("block-line"), + "alt-required": slug("alt-required"), + "alt-empty": slug("alt-empty"), + "web-components": slug("web-components"), + "shadow-dom": slug("shadow-dom"), + "custom-elements": slug("custom-elements"), + "web-manifest": slug("web-manifest"), }; const browserQuestionCollection: QuestionSection = { - title: 'HTML', - icon: 'fluent-emoji:skull', + title: "HTML", + icon: "fluent-emoji:skull", collection: [ { - name: 'Что такое семантические теги и зачем они нужны?', + name: "Что такое семантические теги и зачем они нужны?", slug: slugs.semantic, answer: [ - 'Семантические элементы - это элементы или теги со значением.', - 'Есть теги, которые не описывают контент, который они хранят в себе (например
).', - 'Есть теги, которые описывают структуру документа или контент, который хранится в них ' + - '(например
,
, ,