diff --git a/README.md b/README.md index c811ba051d..c2953fd182 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,7 @@ If there are variations, how best to place indents-welcome:) [refs-contributing]: CONTRIBUTING.md -[refs-docs]: https://feature-sliced.design/docs/intro +[refs-docs]: https://feature-sliced.design/docs [refs-motivation]: https://feature-sliced.design/docs/about/motivation [refs-motivation-why]: https://feature-sliced.design/docs/about/motivation#-почему-не-хватает-существующих-решений diff --git a/docusaurus.config.js b/docusaurus.config.js index 552584ebbe..541fc7fed9 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,6 +1,6 @@ require("dotenv").config(); const path = require("path"); -const { REDIRECTS, SECTIONS, LEGACY_ROUTES } = require("./routes.config"); +const { REDIRECTS, LEGACY_ROUTES } = require("./routes.config"); const DOMAIN = "https://feature-sliced.design/"; const GITHUB_ORG = "https://github.com/feature-sliced"; @@ -32,60 +32,23 @@ const navbar = { items: [ // left { - type: "dropdown", label: "📖 Docs", + to: "/docs", position: "left", - items: [ - { - label: "🔎 Intro", - to: SECTIONS.INTRO.fullPath, - activeBasePath: SECTIONS.INTRO.fullPath, - }, - { - label: "🚀 Get Started", - to: SECTIONS.GET_STARTED.shortPath, - activeBasePath: SECTIONS.GET_STARTED.shortPath, - }, - { - label: "🎯 Guides", - to: SECTIONS.GUIDES.shortPath, - activeBasePath: SECTIONS.GUIDES.shortPath, - }, - { - label: "🧩 Concepts", - to: SECTIONS.CONCEPTS.shortPath, - activeBasePath: SECTIONS.CONCEPTS.shortPath, - }, - { - label: "📚 Reference", - to: SECTIONS.REFERENCE.shortPath, - activeBasePath: SECTIONS.REFERENCE.shortPath, - }, - { - label: "🍰 About", - to: SECTIONS.ABOUT.shortPath, - activeBasePath: SECTIONS.ABOUT.shortPath, - }, - { - label: "💫 Community", - to: SECTIONS.COMMUNITY.fullPath, - activeBasePath: SECTIONS.COMMUNITY.fullPath, - }, - ], }, { - label: "🛠 Examples", - to: SECTIONS.EXAMPLES.fullPath, + label: "💫 Community", + to: "/community", position: "left", }, { - label: "❔ Help", - to: "/nav", + label: "📝 Blog", + to: "/blog", position: "left", }, { - label: "📝 Blog", - to: "/blog", + label: "🛠 Examples", + to: "/examples", position: "left", }, // right @@ -145,7 +108,9 @@ const footer = { { title: "Specs", items: [ - { label: "Documentation", to: "/docs/intro" }, + { label: "Documentation", to: "/docs" }, + { label: "Community", to: "/community" }, + { label: "Help", to: "/nav" }, { label: "Discussions", to: `${GITHUB_DOCS}/discussions` }, ], }, @@ -297,6 +262,8 @@ const algolia = { // contextualSearch: true, }; +const NBSP = " "; + /** @type {Config["themeConfig"]["announcementBar"]} */ const announcementBar = { id: "bar", // Any value that will identify this message. @@ -307,7 +274,11 @@ const announcementBar = { // content: `📚 Documentation refinements are in progress. Stay tuned for updates and share your feedback`, // backgroundColor: "#5c9cb5", // As primary theme // backgroundColor: "#0367d2", - content: `🍰 We're rebranding!  |  ☮️ Stop the war in Ukraine! #NoWar`, // #nowar + content: [ + `🍰 We're rebranding!`, + `❔Help`, + `☮️ Stop the war in Ukraine! #NoWar`, // #nowar + ].join(`${NBSP + NBSP}|${NBSP + NBSP}`), backgroundColor: "#000000", // #nowar textColor: "#fff", // Defaults to `#000`. isCloseable: false, // Defaults to `true`. diff --git a/i18n/en/docusaurus-plugin-content-docs/community/index.mdx b/i18n/en/docusaurus-plugin-content-docs/community/index.mdx index ddc6c3aa36..0e8dc5f912 100644 --- a/i18n/en/docusaurus-plugin-content-docs/community/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/community/index.mdx @@ -15,28 +15,28 @@ Community resources, additional materials ## Main -import Row from "@site/src/shared/ui/row/tmpl.mdx" +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" import { StarOutlined, SearchOutlined, TeamOutlined, VerifiedOutlined } from "@ant-design/icons"; - - - - - - - - - *"Today, the feature can only be used on one page. Next week - on three. And in a month - it may be removed at all. We cannot predict the future, and we need to refrain from premature optimizations every time"* -*See also the example from [quick-start](/docs/get-started/quick-start#normal-approach)* +*See also the example from [tutorial](/docs/get-started/tutorial#normal-approach)* diff --git a/i18n/en/docusaurus-plugin-content-docs/current/get-started/index.mdx b/i18n/en/docusaurus-plugin-content-docs/current/get-started/index.mdx index 7a9ff24199..1eda2983e9 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/get-started/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/get-started/index.mdx @@ -16,22 +16,22 @@ Welcome! This section helps you to get acquainted with the application of Featur ## Main -import Row from "@site/src/shared/ui/row/tmpl.mdx" -import { RocketOutlined, BuildOutlined, SettingOutlined } from "@ant-design/icons"; +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, BuildOutlined, PlaySquareOutlined } from "@ant-design/icons"; - - -layers, each layer is made up of slices and each slice is made up of segments. + +![themed--scheme](/img/visual_schema.jpg) + +The **layers** are standardized across all projects and vertically arranged. Modules on one layer can only interact with modules from the layers strictly below. There are currently seven of them (bottom to top): + +1. `shared` — reusable functionality, detached from the specifics of the project/business. + (e.g. UIKit, libs, API) +2. `entities` — business entities. + (e.g., User, Product, Order) +3. `features` — user interactions, actions that bring business value to the user. + (e.g. SendComment, AddToCart, UsersSearch) +4. `widgets` — compositional layer to combine entities and features into meaningful blocks. + (e.g. IssuesList, UserProfile) +5. `pages` — compositional layer to construct full pages from entities, features and widgets. +6. `processes` — complex inter-page scenarios. + (e.g., authentication) +7. `app` — app-wide settings, styles and providers. + + +Then there are **slices**, which partition the code by business domain. This makes your codebase easy to navigate by keeping logically related modules close together. Slices cannot use other slices on the same layer, and that helps with high cohesion and low coupling. + +Each slice, in turn, consists of **segments**. These are tiny modules that are meant to help with separating code within a slice by its technical purpose. The most common segments are `ui`, `model` (store, actions), `api` and `lib` (utils/hooks), but you can omit some or add more, as you see fit. + +:::note + +In most cases, [it is recommended][ext-disc-api] to place `api` and `config` only in the shared layer + +::: + +## Example + +Let's consider a social network application. + +* `app/` contains setup of routing, store and global styles. +* `processes/` contains the part of authentication that is responsible for reading/writing authentication tokens. +* `pages/` contains the route components for each page in the app, mostly composition, hardly any logic. + +Within that application, let's consider a post card in a news feed. + +* `widgets/` contains the "assembled" post card, with content and interactive buttons that are wired up to the relevant calls on the back-end. +* `features/` contains the interactivity of the card (e.g., like button) and the logic of processing those interactions. +* `entities/` contains the shell of the card with slots for content and the interactive elements. The tile representing the post author is also here, but in a different slice. + +## Advantages + +- **Uniformity** + The code is organized by scope of influence (layers), by domain (slices), and by technical purpose (segments). + This creates a standardized architecture that is easier to comprehend for newcomers. + +- **Controlled reuse of logic** + Each architectural component has its purpose and predictable dependencies. + This keeps a balance between following the **DRY** principle and adaptation possibilities. + +- **Stability in face of changes and refactoring** + A module on a particular layer cannot use other modules on the same layer, or the layers above. + This enables isolated modifications without unforeseen consequences. + +- **Orientation to business and users needs** + App splitting by business domains help to deeper understand, structure and discovery project features. + +## Incremental adoption + +The power of FSD lies in _structured_ decomposition. At its finest, it enables to locate any part of code near-deterministically. However, the level of decomposition is a parameter, and each team can tweak it to strike a balance between simple adoption and the amount of benefits. + +Here's a proposed strategy to migrate an existing codebase to FSD, based on experience: + +1. Start by outlining the `app` and `shared` layers to create a foundation. Usually, these layers are the smallest. + +2. Distribute all of the existing UI across `widgets` and `pages`, even if they have dependencies that violate the rules of FSD. + +3. Start gradually increasing the precision of decomposition by separating `features` and `entities`, turning pages and widgets from logic-bearing layers into purely compositional layers. + +It's advised to refrain from adding new large entities while refactoring or refactoring only certain parts of the project. + +[refs-clean-architecture]: https://medium.com/codex/clean-architecture-for-dummies-df6561d42c94 +[ext-disc-api]: https://github.com/feature-sliced/documentation/discussions/66 +[refs-examples]: /examples +[refs-migration]: /docs/guides/migration +[refs-splitting]: /docs/concepts/app-splitting diff --git a/i18n/en/docusaurus-plugin-content-docs/current/get-started/quick-start.md b/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md similarity index 99% rename from i18n/en/docusaurus-plugin-content-docs/current/get-started/quick-start.md rename to i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md index be45b60f6c..b671438b41 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/get-started/quick-start.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -2,7 +2,7 @@ sidebar_position: 2 --- -# Quick start +# Tutorial Let's consider the application of **Feature-Sliced Design** on the example of TodoApp @@ -493,7 +493,7 @@ export const $tasksList = combine($tasks, (tasks) => Object.values(tasks)); ```tsx title=pages/tasks-list/index.tsx import { useEffect } from "react"; // If you feel confident with @effector/reflect - can use it -// Within the quick-start non-critical +// Within the tutorial non-critical import { useStore } from "effector"; import { Layout, Row, Col, Typography, Spin, Empty } from "antd"; // ~ "shared/ui/{...}" @@ -638,7 +638,7 @@ export const $tasksFiltered = combine( ```tsx title=features/tasks-filters/ui.tsx // If you feel confident with @effector/reflect, you can immediately use it -// As part of quick-start uncritically +// As part of tutorial uncritically import { useStore } from "effector"; import { Radio } from "antd"; // ~ "shared/ui/radio" diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/index.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/index.mdx index 2383807f42..89c35c11b2 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/index.mdx @@ -15,24 +15,24 @@ Small practical examples of the methodology application ## Main -import Row from "@site/src/shared/ui/row/tmpl.mdx" +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" import { UserSwitchOutlined, LayoutOutlined, FontSizeOutlined } from "@ant-design/icons"; - - - - -OVERVIEW-ORIENTED +# Documentation ![feature-sliced-banner](/img/banner.jpg) **Feature-Sliced Design** (FSD) is an architectural methodology for scaffolding front-end applications. Simply put, it's a compilation of rules and conventions on organizing code. The main purpose of this methodology is to make the project more understandable and structured in the face of ever-changing business requirements. -## Is it right for me? - -FSD can be implemented in projects and teams of any size, but there are a few things to keep in mind: - -- This methodology is for front-end projects only. If you're looking for a back-end architecture, consider [Clean Architecture][refs-clean-architecture]. -- A very simple app of a single page might not need the benefits of FSD and suffer from the overhead. However, FSD promotes a nice way of thinking, so feel free to use on the tiniest projects if you want. -- A huge app, the size of the Google Cloud admin dashboard, will require a custom architecture. It could still be based on FSD, by the way. - -FSD doesn't enforce a particular programming language, UI framework or state manager — bring your own or see some [examples][refs-examples]. - -If you have an existing project, fear not — FSD can be adopted incrementally. Just make sure that your team is **in pain** from the current architecture, otherwise a switch might not be worth it. - -## Overview - -In FSD, a project consists of _layers_, each layer is made up of _slices_ and each slice is made up of _segments_. - -![themed--scheme](/img/visual_schema.jpg) - -The layers are standardized across all projects and vertically arranged. Modules on one layer can only interact with modules from the layers strictly below. There are currently seven of them (bottom to top): - -1. **Shared** — reusable functionality, detached from the specifics of the project/business. -2. **Entities** — business entities (e.g., User, Product, Order). -3. **Features** — user interactions, actions that bring business value to the user. -4. **Widgets** — compositional layer to combine entities and features into meaningful blocks. -5. **Pages** — compositional layer to construct full pages from entities, features and widgets. -6. **Processes** — complex inter-page scenarios (e.g., authentication). -7. **App** — app-wide settings, styles and providers. - -Then there are slices, which partition the code by business domain. This makes your codebase easy to navigate by keeping logically related modules close together. Slices cannot use other slices on the same layer, and that helps with high cohesion and low coupling. - -Each slice, in turn, consists of segments. These are tiny modules that are meant to help with separating code within a slice by its technical purpose. The most common segments are `ui`, `model`, `api` and `lib`, but you can omit some or add more, as you see fit. - -### Decomposition example - -Let's consider a social network application. - -* `app/` contains setup of routing, store and global styles. -* `processes/` contains the part of authentication that is responsible for reading/writing authentication tokens. -* `pages/` contains the route components for each page in the app, mostly composition, hardly any logic. - -Within that application, let's consider a post card in a news feed. - -* `widgets/` contains the "assembled" post card, with content and interactive buttons that are wired up to the relevant calls on the back-end. -* `features/` contains the interactivity of the card (e.g., like button) and the logic of processing those interactions. -* `entities/` contains the shell of the card with slots for content and the interactive elements. The tile representing the post author is also here, but in a different slice. - -### Advantages - -- **Uniformity** - The code is organized by scope of influence (layers), by domain (slices), and by technical purpose (segments). - This creates a standardized architecture that is easier to comprehend for newcomers. - -- **Controlled reuse of logic** - Each architectural component has its purpose and predictable dependencies. - This keeps a balance between following the **DRY** principle and adaptation possibilities. - -- **Stability in face of changes and refactoring** - A module on a particular layer cannot use other modules on the same layer, or the layers above. - This enables isolated modifications without unforeseen consequences. - - -## Incremental adoption - -The power of FSD lies in _structured_ decomposition. At its finest, it enables to locate any part of code near-deterministically. However, the level of decomposition is a parameter, and each team can tweak it to strike a balance between simple adoption and the amount of benefits. - -Here's a proposed strategy to migrate an existing codebase to FSD, based on experience: - -1. Start by outlining the `app` and `shared` layers to create a foundation. Usually, these layers are the smallest. - -2. Distribute all of the existing UI across `widgets` and `pages`, even if they have dependencies that violate the rules of FSD. - -3. Start gradually increasing the precision of decomposition by separating `features` and `entities`, turning pages and widgets from logic-bearing layers into purely compositional layers. +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, ThunderboltOutlined, FundViewOutlined } from "@ant-design/icons"; +import Link from "@docusaurus/Link"; -It's advised to refrain from adding new large entities while refactoring or refactoring only certain parts of the project. + + -## What's next? +
-import Row from "@site/src/shared/ui/row/tmpl.mdx" -import { RocketOutlined, ThunderboltOutlined, FundViewOutlined } from "@ant-design/icons"; -import Link from "@docusaurus/Link"; - - - - - - - - - -[refs-examples]: /examples - -[refs-clean-architecture]: https://medium.com/codex/clean-architecture-for-dummies-df6561d42c94 diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx index f05cffb760..e9f045f103 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -17,22 +17,22 @@ A detailed description of the concepts on which the methodology is based. ## Main -import Row from "@site/src/shared/ui/row/tmpl.mdx" +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" import { MenuOutlined, GoldOutlined, ReadOutlined } from "@ant-design/icons"; - - - - - - - - - - - *"Сегодня фича может использоваться только на одной странице. На следующей неделе - на трех. А через месяц - ее может не быть совсем. Мы не можем предсказывать будущее, и нужно каждый раз воздерживаться от преждевременных оптимизаций"* -*См. также пример из [quick-start](/docs/get-started/quick-start#usual-approach)* +*См. также пример из [tutorial](/docs/get-started/tutorial#usual-approach)* diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/index.mdx index 622b804a04..17e3fbed26 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/index.mdx @@ -16,22 +16,22 @@ pagination_prev: intro ## Главное {#main} -import Row from "@site/src/shared/ui/row/tmpl.mdx" -import { RocketOutlined, BuildOutlined, SettingOutlined } from "@ant-design/icons"; +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, BuildOutlined, PlaySquareOutlined } from "@ant-design/icons"; - - -слоев (layers), каждый слой состоит из слайсов (slices) и каждый слайс состоит из сегментов (segments). + +![themed--scheme](/img/visual_schema.jpg) + +**Слои** стандартизированы во всех проектах и расположены вертикально. Модули на одном слое могут взаимодействовать лишь с модулями, находящимися на слоях строго ниже. На данный момент слоев семь (снизу вверх): + +1. `shared` — переиспользуемый код, не имеющий отношения к специфике приложения/бизнеса. + (например, UIKit, libs, API) +2. `entities` (сущности) — бизнес-сущности (например, User, Product или Order). + (например, User, Product, Order) +3. `features` (фичи) — взаимодействия с пользователем, действия, которые несут бизнес-ценность для пользователя. + (например, SendComment, AddToCart, UsersSearch) +4. `widgets` (виджеты) — композиционный слой для соединения сущностей и фич в самостоятельные блоки + (например, IssuesList, UserProfile). +5. `pages` (страницы) — композиционный слой для сборки полноценных страниц из сущностей, фич и виджетов. +6. `processes` — сложные сценарии, покрывающие несколько страниц. + (например, авторизация) +7. `app` — настройки, стили и провайдеры для всего приложения. + +Затем есть **слайсы**, разделяющие код по предметной области. Они группируют логически связанные модули, что облегчает навигацию по кодовой базе. Слайсы не могут использовать другие слайсы на том же слое, что обеспечивает высокий уровень [_связности_][refs-wiki-cohesion] (cohesion) при низком уровне [_связанности_][refs-wiki-coupling] (coupling). + +В свою очередь, каждый слайс состоит из **сегментов**. Это маленькие модули, главная задача которых — разделить код внутри слайса по техническому назначению. Самые распространенные сегменты — `ui`, `model` (store, actions), `api` и `lib` (utils/hooks), но в вашем слайсе может не быть каких-то сегментов, могут быть другие, по вашему усмотрению. + +:::note + +В большинстве случаев [рекомендуется][ext-disc-api] располагать `api` и `config` только в shared-слое + +::: + +## Пример {#example} + +Рассмотрим приложение социальной сети. + +* `app/` содержит настройку роутера, глобальные хранилища и стили. +* `processes/` содержит часть аутентификации, отвечающую за чтение/запись токенов аутентификации. +* `pages/` содержит компоненты роутов на каждую страницу в приложении, преимущественно композирующие, по возможности, без собственной логики. + +В рамках этого приложения рассмотрим карточку поста в ленте новостей. + +* `widgets/` содержит "собранную" карточку поста, с содержимым и интерактивными кнопками, в которые вшиты запросы к бэкенду. +* `features/` содержит всю интерактивность карточки (например, кнопку лайка) и логику обработки этой интерактивности. +* `entities/` содержит скелет карточки со слотами под интерактивные элементы. Компонент, демонстрирующий автора поста, также находится в этой папке, но в другом слайсе. + +### Преимущества {#advantages} + +- **Единообразие** + Код распределяется согласно области влияния (слой), предметной области (слайс) и техническому назначению (сегмент). + Благодаря этому архитектура стандартизируется и становится более простой для ознакомления. + +- **Контролируемое переиспользование логики** + Каждый компонент архитектуры имеет свое назначение и предсказуемый список зависимостей. + Благодаря этому сохраняется баланс между соблюдением принципа **DRY** и возможностью адаптировать модуль под разные цели. + +- **Устойчивость к изменениям и рефакторингу** + Один модуль не может использовать другой модуль, расположенный на том же слое или на слоях выше. + Благодаря этому приложение можно изолированно модифицировать под новые требования без непредвиденных последствий. + +- **Ориентированность на потребности бизнеса и пользователей** + Разбиение приложение по бизнес-доменам помогает глубже понять, структурировать и находить фичи проекта. + +## Постепенное внедрение {#incremental-adoption} + +Сила FSD в _структурированной_ декомпозиции. В лучшей форме, FSD позволяет найти место для любой части кода почти однозначно. Однако, уровень декомпозиции — это параметр, и любая команда может подстроить его для оптимального баланса между легкостью внедрения и преимуществами. + +Предлагаем следующую стратегию для миграции существующей кодовой базы на FSD, проверенную опытом: + +1. Вырезать слои `app` и `shared`, чтобы иметь опору для последующих этапов. Эти слои получатся тонкими и простыми, пусть такими и остаются. + +2. Вынести весь интерфейс, связанный с бизнесом, распределить по виджетам и страницам, даже если в них пока что будут зависимости, нарушающие правила FSD. + +3. Постепенно наращивать степень декомпозиции, выделяя `features` и `entities`. Превращать страницы и виджеты из перегруженных логикой слоёв в чисто композиционные слои. + +Рекомендуется воздержаться от добавления новых крупных сущностей во время рефакторинга, а также рефакторинга по частям. + +[refs-clean-architecture]: https://medium.com/codex/clean-architecture-for-dummies-df6561d42c94 +[ext-disc-api]: https://github.com/feature-sliced/documentation/discussions/66 +[refs-examples]: /examples +[refs-migration]: /docs/guides/migration +[refs-splitting]: /docs/concepts/app-splitting +[refs-wiki-cohesion]: https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) +[refs-wiki-coupling]: https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/quick-start.md b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md similarity index 99% rename from i18n/ru/docusaurus-plugin-content-docs/current/get-started/quick-start.md rename to i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md index 8879365703..0c59ec7b2c 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/quick-start.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -2,7 +2,7 @@ sidebar_position: 2 --- -# Быстрый старт +# Туториал Рассмотрим применение **Feature-Sliced Design** на примере TodoApp @@ -491,7 +491,7 @@ export const $tasksList = combine($tasks, (tasks) => Object.values(tasks)); ```tsx title=pages/tasks-list/index.tsx import { useEffect } from "react"; // Если чувствуете себя уверенно с @effector/reflect - можете сразу использовать его -// В рамках quick-start некритично +// В рамках туториала некритично import { useStore } from "effector"; import { Layout, Row, Col, Typography, Spin, Empty } from "antd"; // ~ "shared/ui/{...}" @@ -636,7 +636,7 @@ export const $tasksFiltered = combine( ```tsx title=features/tasks-filters/ui.tsx // Если чувствуете себя уверенно с @effector/reflect - можете сразу использовать его -// В рамках quick-start некритично +// В рамках туториала некритично import { useStore } from "effector"; import { Radio } from "antd"; // ~ "shared/ui/radio" diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/index.mdx index 7240c556af..409070b3d7 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/index.mdx @@ -15,24 +15,24 @@ pagination_prev: guides/index ## Главное {#main} -import Row from "@site/src/shared/ui/row/tmpl.mdx" +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" import { UserSwitchOutlined, LayoutOutlined, FontSizeOutlined } from "@ant-design/icons"; - - - - -OVERVIEW-ORIENTED +# Документация ![feature-sliced-banner](/img/banner.jpg) **Feature-Sliced Design** (FSD) — это архитектурная методология для проектирования frontend-приложений. Проще говоря, это свод правил и соглашений по организации кода. Главная цель методологии — сделать проект понятным и структурированным, особенно в условиях регулярного изменения требований бизнеса. -## Подходит ли это мне? {#is-it-right-for-me} - -FSD подходит для проектов и команд любого размера с некоторыми оговорками: - -- Эта методология исключительно для фронтенда. Если вы ищете архитектуру для бэкенда, обратите внимание на [Clean Architecture][refs-clean-architecture]. -- Если вы разрабатываете очень простое приложение из одной странички на FSD, преимущества методологии вряд ли понадобятся, а вот разработка может замедлиться. Однако, FSD помогает стандартизированно мыслить о фронтенд-приложениях, так что смело используйте даже на маленьких проектах, если знаете, для чего она вам. -- Огромное приложение, соизмеримое с админ-панелью Google Cloud, потребует специализированной архитектуры. FSD в данном случае может выступать в качестве отправной точки. - -Методология не привязана к конкретному языку программирования, UI-фреймворку или менеджеру состояния — подойдет любой (см. [примеры использования][refs-examples]). - -Если у вас уже есть проект, не переживайте — FSD можно внедрять постепенно. Главный вопрос, который стоит задать команде: "**Eсть ли боль** при разработке проекта?" Если боли нет, возможно, переход делать не стоит. - -## Краткий обзор {#overview} - -Проект на FSD состоит из _слоев_ (layers), каждый слой состоит из _слайсов_ (slices) и каждый слайс состоит из _сегментов_ (segments). - -![themed--scheme](/img/visual_schema.jpg) - -Слои стандартизированы во всех проектах и расположены вертикально. Модули на одном слое могут взаимодействовать лишь с модулями, находящимися на слоях строго ниже. На данный момент слоев семь (снизу вверх): - -1. **Shared** — переиспользуемый код, не имеющий отношения к специфике приложения/бизнеса. -2. **Entities** (сущности) — бизнес-сущности (например, User, Product или Order). -3. **Features** (фичи) — взаимодействия с пользователем, действия, которые несут бизнес-ценность для пользователя. -4. **Widgets** (виджеты) — композиционный слой для соединения сущностей и фич в самостоятельные блоки. -5. **Pages** (страницы) — композиционный слой для сборки полноценных страниц из сущностей, фич и виджетов. -6. **Processes** — сложные сценарии, покрывающие несколько страниц (например, аутентификация). -7. **App** — настройки, стили и провайдеры для всего приложения. - -Затем есть слайсы, разделяющие код по предметной области. Они группируют логически связанные модули, что облегчает навигацию по кодовой базе. Слайсы не могут использовать другие слайсы на том же слое, что обеспечивает высокий уровень [_связности_][refs-wiki-cohesion] (cohesion) при низком уровне [_связанности_][refs-wiki-coupling] (coupling). - -В свою очередь, каждый слайс состоит из сегментов. Это маленькие модули, главная задача которых — разделить код внутри слайса по техническому назначению. Самые распространенные сегменты — `ui`, `model`, `api` и `lib`, но в вашем слайсе может не быть каких-то сегментов, могут быть другие, по вашему усмотрению. - -### Пример декомпозиции {#decomposition-example} - -Рассмотрим приложение социальной сети. - -* `app/` содержит настройку роутера, глобальные хранилища и стили. -* `processes/` содержит часть аутентификации, отвечающую за чтение/запись токенов аутентификации. -* `pages/` содержит компоненты роутов на каждую страницу в приложении, преимущественно композирующие, по возможности, без собственной логики. - -В рамках этого приложения рассмотрим карточку поста в ленте новостей. - -* `widgets/` содержит "собранную" карточку поста, с содержимым и интерактивными кнопками, в которые вшиты запросы к бэкенду. -* `features/` содержит всю интерактивность карточки (например, кнопку лайка) и логику обработки этой интерактивности. -* `entities/` содержит скелет карточки со слотами под интерактивные элементы. Компонент, демонстрирующий автора поста, также находится в этой папке, но в другом слайсе. - -### Преимущества {#advantages} - -- **Единообразие** - Код распределяется согласно области влияния (слой), предметной области (слайс) и техническому назначению (сегмент). - Благодаря этому архитектура стандартизируется и становится более простой для ознакомления. - -- **Контролируемое переиспользование логики** - Каждый компонент архитектуры имеет свое назначение и предсказуемый список зависимостей. - Благодаря этому сохраняется баланс между соблюдением принципа **DRY** и возможностью адаптировать модуль под разные цели. - -- **Устойчивость к изменениям и рефакторингу** - Один модуль не может использовать другой модуль, расположенный на том же слое или на слоях выше. - Благодаря этому приложение можно изолированно модифицировать под новые требования без непредвиденных последствий. - - -## Постепенное внедрение {#incremental-adoption} - -Сила FSD в _структурированной_ декомпозиции. В лучшей форме, FSD позволяет найти место для любой части кода почти однозначно. Однако, уровень декомпозиции — это параметр, и любая команда может подстроить его для оптимального баланса между легкостью внедрения и преимуществами. - -Предлагаем следующую стратегию для миграции существующей кодовой базы на FSD, проверенную опытом: - -1. Вырезать слои `app` и `shared`, чтобы иметь опору для последующих этапов. Эти слои получатся тонкими и простыми, пусть такими и остаются. - -2. Вынести весь интерфейс, связанный с бизнесом, распределить по виджетам и страницам, даже если в них пока что будут зависимости, нарушающие правила FSD. - -3. Постепенно наращивать степень декомпозиции, выделяя `features` и `entities`. Превращать страницы и виджеты из перегруженных логикой слоёв в чисто композиционные слои. +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, ThunderboltOutlined, FundViewOutlined } from "@ant-design/icons"; +import Link from "@docusaurus/Link"; -Рекомендуется воздержаться от добавления новых крупных сущностей во время рефакторинга, а также рефакторинга по частям. + -## Что дальше? {#whats-next} + -import Row from "@site/src/shared/ui/row/tmpl.mdx" -import { RocketOutlined, ThunderboltOutlined, FundViewOutlined } from "@ant-design/icons"; -import Link from "@docusaurus/Link"; +
- - - - - - - - -[refs-clean-architecture]: https://medium.com/codex/clean-architecture-for-dummies-df6561d42c94 -[refs-wiki-cohesion]: https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) -[refs-wiki-coupling]: https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) - -[refs-examples]: /examples diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx index a6623e6c05..bf13470880 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -17,22 +17,22 @@ pagination_prev: concepts/index ## Главное {#main} -import Row from "@site/src/shared/ui/row/tmpl.mdx" +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" import { MenuOutlined, GoldOutlined, ReadOutlined } from "@ant-design/icons"; - - - { // FIXME: temp, resolve later // @returns { from, to }[] -const SECTIONS_REDIRECTS = Object.values(SECTIONS) - // Custom filtering - .filter(({ shortPath, fullPath }) => shortPath !== fullPath) - .map(({ shortPath, fullPath }) => ({ - from: shortPath, - to: fullPath, - })); +const SECTIONS_REDIRECTS = Object.values(SECTIONS).map(({ shortPath, fullPath }) => ({ + from: shortPath, + to: fullPath, +})); // !!! FIXME: refactor later! const _TOTAL_ROUTES = [ @@ -296,10 +255,10 @@ const _TOTAL_ROUTES = [ "/docs/concepts/public-api", "/docs/concepts/signals", "/docs/get-started", - "/docs/get-started/basics", + "/docs/get-started/overview", "/docs/get-started/cheatsheet", "/docs/get-started/faq", - "/docs/get-started/quick-start", + "/docs/get-started/tutorial", "/docs/guides", "/docs/guides/examples", "/docs/guides/examples/auth", @@ -319,7 +278,7 @@ const _TOTAL_ROUTES = [ "/docs/guides/migration/from-legacy", "/docs/guides/migration/from-v1", "/docs/guides/tech/with-nextjs", - "/docs/intro", + "/docs/", "/docs/privacy", "/docs/reference", "/docs/reference/glossary", @@ -343,7 +302,6 @@ const I18N_REDIRECTS = _TOTAL_ROUTES.map((route) => ({ const REDIRECTS = [...SECTIONS_REDIRECTS, ...LEGACY_ROUTES_REDIRECTS, ...I18N_REDIRECTS]; module.exports = { - SECTIONS, LEGACY_ROUTES, REDIRECTS, }; diff --git a/src/app/index.scss b/src/app/index.scss index c2de09ac63..33d2cadaba 100644 --- a/src/app/index.scss +++ b/src/app/index.scss @@ -117,6 +117,13 @@ iframe { border-radius: 16px; } +mark { + padding: 2px; + color: #ffffff; + background-color: var(--ifm-color-primary-neutral); + border-radius: 4px; +} + /* media */ /* TODO: connect as file */ @@ -182,6 +189,8 @@ iframe { } /* I love adaptive styles... */ + +/* FIXME: add unified adaptive breakpoints */ @media (max-width: 1080px) { .navbar__item { padding: var(--ifm-navbar-item-padding-vertical) 0.25rem; @@ -194,6 +203,12 @@ iframe { } } +@media (max-width: 600px) { + [role="banner"] { + font-size: 1rem; // #nowar + } +} + a[download] { transition: 0.25s; @@ -237,7 +252,7 @@ a[download] { } } - &__logo { - margin-right: 0; - } + // &__logo { + // margin-right: 0; + // } } diff --git a/src/app/theme.scss b/src/app/theme.scss index ddd429ab8e..84a2da7ec3 100644 --- a/src/app/theme.scss +++ b/src/app/theme.scss @@ -39,6 +39,7 @@ --ifm-color-primary-lightest: #6b9ee1; --ifm-color-primary-grad1: #29bedc; --ifm-color-primary-grad2: #517aed; + --ifm-color-primary-neutral: #4a7ec2c6; --ifm-font-family-base: 'Ubuntu', system-ui, -apple-system, segoe ui, roboto, ubuntu, cantarell, noto sans, sans-serif, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; --ifm-heading-font-family: 'Overpass', var(--ifm-font-family-base); } diff --git a/src/features/header/ui.jsx b/src/features/header/ui.jsx index f9d99ba833..ff164691cc 100644 --- a/src/features/header/ui.jsx +++ b/src/features/header/ui.jsx @@ -14,7 +14,7 @@ export function Header() {

{siteConfig.title}

{translate({ id: "features.hero.tagline" })}

- + {translate({ id: "features.hero.get_started" })} diff --git a/src/pages/nav/index.jsx b/src/pages/nav/index.jsx index 84d9cd62e6..85829a753e 100644 --- a/src/pages/nav/index.jsx +++ b/src/pages/nav/index.jsx @@ -5,7 +5,7 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; import { translate } from "@docusaurus/Translate"; -import { Row } from "@site/src/shared/ui/row"; +import { NavCard } from "@site/src/shared/ui/nav-card"; import styles from "./styles.module.scss"; const NavPage = () => { @@ -37,7 +37,7 @@ const GroupItems = () => {

⚡️ {routesBatch.details}

{routesBatch.children.map((route) => ( - - Documentation + Documentation diff --git a/src/shared/ui/row/index.jsx b/src/shared/ui/nav-card/index.jsx similarity index 79% rename from src/shared/ui/row/index.jsx rename to src/shared/ui/nav-card/index.jsx index 1ccd63cace..24543abf75 100644 --- a/src/shared/ui/row/index.jsx +++ b/src/shared/ui/nav-card/index.jsx @@ -6,11 +6,12 @@ import { ga } from "@site/src/shared/lib/ga"; import styles from "./styles.module.scss"; /** - * Row card for linking + * NavCard for linking * @see https://docusaurus.io/docs/next/markdown-features/react#importing-markdown + * @param {import('./types').Props} props */ -export const Row = (props) => { - const { title, description, to, Icon, tags, className, disabled } = props; +export const NavCard = (props) => { + const { title, description, to, Icon, tags, className, disabled, theme = "default" } = props; const handleClick = useCallback(() => { ga.sendEvent({ category: ga.CATEGORIES.full, @@ -22,7 +23,12 @@ export const Row = (props) => { return ( @@ -49,4 +55,4 @@ const RowIcon = ({ Icon }) => { return ; }; -export default Row; +export default NavCard; diff --git a/src/shared/ui/row/styles.module.scss b/src/shared/ui/nav-card/styles.module.scss similarity index 60% rename from src/shared/ui/row/styles.module.scss rename to src/shared/ui/nav-card/styles.module.scss index 57d7d6cdf5..4336516e74 100644 --- a/src/shared/ui/row/styles.module.scss +++ b/src/shared/ui/nav-card/styles.module.scss @@ -46,6 +46,37 @@ margin-bottom: 0; } +// themes +.miniTheme { + padding: 20px 30px; + + & .title { + font-size: 1rem; + } + + & .details { + filter: grayscale(1); + } + + &:hover .details { + filter: grayscale(0); + } +} + +.primaryTheme { + color: #ffffff; + background-color: var(--ifm-color-primary); + + &:hover { + color: #ffffff; + box-shadow: 0 2px 10px 0 var(--ifm-color-primary-neutral); + } +} + +// dark-mode html[data-theme="dark"] .root { - background: var(--ifm-color-gray-900); + &.defaultTheme, + &.miniTheme { + background: var(--ifm-color-gray-900); + } } diff --git a/src/shared/ui/nav-card/tmpl.mdx b/src/shared/ui/nav-card/tmpl.mdx new file mode 100644 index 0000000000..855bd81e7f --- /dev/null +++ b/src/shared/ui/nav-card/tmpl.mdx @@ -0,0 +1,3 @@ +import NavCard from "./index.jsx"; + + diff --git a/src/shared/ui/nav-card/types.d.ts b/src/shared/ui/nav-card/types.d.ts new file mode 100644 index 0000000000..7f8daf9c40 --- /dev/null +++ b/src/shared/ui/nav-card/types.d.ts @@ -0,0 +1,12 @@ +import type { ReactNode } from "react"; + +export type Props = { + title: ReactNode; + description: ReactNode; + to: string; + Icon: string | any; + tags?: string; + className?: string; + disabled?: boolean; + theme?: "default" | "mini" | "primary"; +}; diff --git a/src/shared/ui/row/tmpl.mdx b/src/shared/ui/row/tmpl.mdx deleted file mode 100644 index 59e2f7bcf4..0000000000 --- a/src/shared/ui/row/tmpl.mdx +++ /dev/null @@ -1,3 +0,0 @@ -import Row from "./index.jsx"; - -