diff --git a/.stylelintrc.mjs b/.stylelintrc.mjs index 99ae9d3..8190971 100644 --- a/.stylelintrc.mjs +++ b/.stylelintrc.mjs @@ -7,14 +7,7 @@ const config = { ], plugins: ['stylelint-order', './config/stylelint/restrict-apply.js'], rules: { - 'custom-rules/restrict-apply': [ - true, { - allowedPatterns: [ - '^text-(sm|base|lg|xl|\\d+)$', - '^border', - ], - }, - ], + 'custom-rules/restrict-apply': [true, { allowedPatterns: [] }], 'declaration-empty-line-before': null, 'function-no-unknown': [ true, @@ -104,7 +97,6 @@ const config = { { ignoreAtRules: [ 'tailwind', - 'apply', 'include', 'variants', 'responsive', diff --git a/README.md b/README.md index 275bacb..5241b00 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ > Самое удобное приложение для записи результатов тренировок (: +⠀ + - ✨🎨 Разработан [дизайн в Figma](https://www.figma.com/design/l7WmZZ7WKEr3YnVNdibxGD/Mobile-App?node-id=250-793&t=7fycS0Obh0DIcwXF-1) - Собственный [UI Kit](/src/shared/ui/) - Серверный рендеринг и [AppRouter](https://nextjs.org/docs/app) @@ -17,6 +19,7 @@ ![React 19](https://img.shields.io/badge/React_19-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) ![TypeScript 5](https://img.shields.io/badge/TypeScript_5-007ACC?style=for-the-badge&logo=typescript&logoColor=white) ![Module SCSS](https://img.shields.io/badge/module_scss-CC6699?style=for-the-badge&logo=sass&logoColor=white) +![Feature-Sliced Design](https://img.shields.io/badge/FSD-3481FE?style=for-the-badge&logo=flat&logoColor=white) ![GIT](https://img.shields.io/badge/CI_/_CD-000000?style=for-the-badge&logo=github&logoColor=white) ![ESLint](https://img.shields.io/badge/ESLint-4B32C3?style=for-the-badge&logo=ESLint&logoColor=white) ![stylelint](https://img.shields.io/badge/stylelint-263238?style=for-the-badge&logo=stylelint&logoColor=white) @@ -27,7 +30,7 @@ > Продемонстрировать свои навыки, это не про «усложнить проект»... > *(всевозможные самописные утилиты, хуки, размазывание не переиспользуемого функционала по всей архитектуре, тесты на всё подряд)*. -> ⠀ +> ~ > Настоящее мастерство находится в простоте `^-^` ⠀ @@ -55,10 +58,13 @@ ##### SCSS -- [[custom-rules/restrict-apply](./config/stylelint/restrict-apply.js)] `@apply` можно использовать только для: - - размера текста: `text-sm` | `text-base` и т.п. - - border: `border...` и т.п. -- [[custom-rules/scss-import-name](./config/eslint/scss-import-name.js)] Импорт стилей из `.module.scss` нужно называть `styles` +- [[custom-rules/restrict-apply](./config/stylelint/restrict-apply.js)] `@apply` запрещено использовать; +- [[custom-rules/scss-import-name](./config/eslint/scss-import-name.js)] Импорт стилей из `.module.scss` нужно называть `styles`. + +##### Tailwind + +- Добавлять пользовательские цвета нужно в `/shared/theme.scss` формата RGB! Далее нужно добавить этот цвет в `/tailwind.config.ts`. + - Использовать переменную цвета нужно строго через `theme('colors.base.{50-950}')`. Через `var(--color-base-{50-950})` использовать запрещено! --- diff --git a/config/stylelint/restrict-apply.js b/config/stylelint/restrict-apply.js index 363b1a0..25ea263 100644 --- a/config/stylelint/restrict-apply.js +++ b/config/stylelint/restrict-apply.js @@ -3,7 +3,7 @@ const stylelint = require('stylelint'); const ruleName = 'custom-rules/restrict-apply'; const messages = stylelint.utils.ruleMessages(ruleName, { - invalid: value => `The class "${value}" is not allowed in @apply.`, + invalid: (value) => `The class "${value}" is not allowed in @apply.`, }); module.exports = stylelint.createPlugin( @@ -21,7 +21,7 @@ module.exports = stylelint.createPlugin( classes.forEach((className) => { const isAllowed = allowedPatterns.some( - pattern => new RegExp(pattern).test(className), + (pattern) => new RegExp(pattern).test(className), ); if (!isAllowed) { diff --git a/config/tailwind/colors.ts b/config/tailwind/colors.ts new file mode 100644 index 0000000..2232579 --- /dev/null +++ b/config/tailwind/colors.ts @@ -0,0 +1,9 @@ +export const withOpacity = (variable: string): string => + // @ts-ignore + (test) => { + if (test.opacityValue === undefined) { + return `rgb(var(--color-${variable}))`; + } + + return `rgba(var(--color-${variable}), ${test.opacityValue})`; + }; diff --git a/eslint.config.mjs b/eslint.config.mjs index 2b470e1..87bbbf2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -222,8 +222,11 @@ const eslintConfig = [ rules: { 'max-len': 'off' }, }, { - files: ['**/config/**/*.js'], - rules: { '@typescript-eslint/no-require-imports': 'off' }, + files: ['**/config/**/*.{js,ts}'], + rules: { + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-require-imports': 'off', + }, }, ]; diff --git a/src/app/(with-navbar)/settings/ui/SettingsContent.tsx b/src/app/(with-navbar)/settings/ui/SettingsContent.tsx index 790e1a3..fe31df5 100644 --- a/src/app/(with-navbar)/settings/ui/SettingsContent.tsx +++ b/src/app/(with-navbar)/settings/ui/SettingsContent.tsx @@ -1,5 +1,7 @@ 'use client'; +import { useTheme } from 'next-themes'; + import { ExportOutlineIcon, FlashOutlineIcon, @@ -11,78 +13,89 @@ import { } from '@/shared/icons'; import { Button, Section } from '@/shared/ui'; +import { ThemesModal } from '@/features/ThemesModal'; + import styles from './settingsContent.module.scss'; -export const SettingsContent = () => ( - <> -
, - onClick: () => { /* void */ }, - title: 'Тренировки', - }, - { - color: '#FFB21A', - icon: , - onClick: () => { /* void */ }, - title: 'Настроить группы', - }, - { - color: '#FA4838', - icon: , - onClick: () => { /* void */ }, - title: 'Упражнения', - }, - ]} - /> -
, - onClick: () => { /* void */ }, - rightText: 'Русский', - title: 'Язык', - }, - { - color: '#5AADF2', - icon: , - onClick: () => { /* void */ }, - rightText: 'Как в системе', - title: 'Оформление', - }, - ]} - /> -
, - onClick: () => { /* void */ }, - title: 'Импорт настроек', - }, - { - color: '#D15347', - description: 'Сохранить файл', - icon: , - onClick: () => { /* void */ }, - title: 'Экспорт настроек', - }, - ]} - /> - - -); +const getThemeName = (theme: string | undefined) => { + switch (theme) { + case 'system': + return 'Как в системе'; + case 'dark': + return 'Темная тема'; + case 'light': + return 'Светлая тема'; + default: + return 'Тема не выбрана'; + } +}; + +export const SettingsContent = () => { + const { theme } = useTheme(); + + return ( + <> +
+ } + title="Тренировки" + /> + } + title="Настроить группы" + /> + } + showDivider={false} + title="Упражнения" + /> +
+
+ } + rightText="Русский" + title="Язык" + /> + + } + rightText={getThemeName(theme)} + showDivider={false} + title="Оформление" + /> + +
+
+ } + title="Импорт настроек" + /> + } + showDivider={false} + title="Экспорт настроек" + /> +
+ + + ); +}; diff --git a/src/app/globals.scss b/src/app/globals.scss index 22076b1..5595a42 100644 --- a/src/app/globals.scss +++ b/src/app/globals.scss @@ -7,11 +7,6 @@ body { background: linear-gradient(90deg, theme('colors.base.950') 15px, transparent 1%) 50%, linear-gradient(theme('colors.base.950') 15px, theme('colors.base.800') 1%) 0, hsl(0deg 0% 100% / 16%); background-size: 16px 16px; - - [data-mode="light"] & { - background: linear-gradient(90deg, theme('colors.base.100') 15px, transparent 1%) 50%, linear-gradient(theme('colors.base.100') 15px, theme('colors.base.300') 1%) 0, hsl(0deg 0% 100% / 16%); - background-size: 16px 16px; - } } ::-webkit-scrollbar { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7b8273e..4b15250 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,6 +7,7 @@ import type { Metadata } from 'next'; import './globals.scss'; import '@/shared/styles/custom.scss'; +import '@/shared/styles/theme.scss'; const inter = Inter({ subsets: ['cyrillic', 'latin'], @@ -26,7 +27,7 @@ const RootLayout = ({ children }: IRootLayout) => ( ( - + {children}