Skip to content

feat: new sliders#123

Merged
hmbanan666 merged 1 commit intomainfrom
sliders
Sep 2, 2025
Merged

feat: new sliders#123
hmbanan666 merged 1 commit intomainfrom
sliders

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Sep 2, 2025

Summary by CodeRabbit

  • New Features

    • Added horizontally scrollable Stories and Recommended sliders on the home page.
    • Introduced a Categories slider menu for quick category navigation.
    • Reworked category sections to display available products per category.
    • Added a User Points card on the user page.
  • UI/Style

    • Improved City Selector spacing and typography.
    • Applied safe-area adjustments to the main layout for better display in Telegram.
  • Refactor

    • Consolidated and replaced the previous category block with new catalog components.

@hmbanan666 hmbanan666 self-assigned this Sep 2, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 2, 2025

Walkthrough

Introduces new catalog slider components and a relocated CategoryBlock under catalog/, updates the index page to compose these components, tweaks CitySelector UI, adds a UserPointsCard and updates user page content, and shifts tg-safe-area from nuxt.config rootAttrs to the default layout’s main element. Removes the old CategoryBlock component.

Changes

Cohort / File(s) Summary of changes
Catalog UI components (new)
apps/storefront-telegram/app/components/catalog/CategoriesSliderMenu.vue, .../catalog/RecommendedSlider.vue, .../catalog/StoriesSlider.vue
Added presentational sliders for categories, recommended items, and stories; pull categories from useMenuStore() where applicable; static content for recommended and stories.
CategoryBlock relocation
apps/storefront-telegram/app/components/CategoryBlock.vue (deleted), .../components/catalog/CategoryBlock.vue (added)
Removed legacy CategoryBlock.vue from components root; added new catalog/CategoryBlock.vue with prop categoryId: string, fetching category from useMenuStore() and rendering filtered products in a grid.
Index page composition
apps/storefront-telegram/app/pages/index.vue
Replaced greeting and single CategoryBlock with CatalogStoriesSlider, CatalogRecommendedSlider, CatalogCategoriesSliderMenu, and per-category CatalogCategoryBlock rendering. Removed clientStore usage.
User page and card
apps/storefront-telegram/app/pages/user.vue, .../components/UserPointsCard.vue
Added UserPointsCard component showing client full name and static 5% value; updated user page layout to include the card and placeholder menu heading.
City selector UI tweaks
apps/storefront-telegram/app/components/CitySelector.vue
Added ui props to UDrawer (content height, margin, overlay class) and UCheckboxGroup (alignment, label size). No logic changes.
Safe area class move
apps/storefront-telegram/app/layouts/default.vue, apps/storefront-telegram/nuxt.config.ts
Removed class: 'tg-safe-area' from app.rootAttrs; added tg-safe-area to <main> class in default layout.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant IndexPage
  participant MenuStore as useMenuStore()
  participant CatMenu as CategoriesSliderMenu
  participant Stories as StoriesSlider
  participant Reco as RecommendedSlider
  participant CatBlock as CategoryBlock
  participant ProductCard

  User->>IndexPage: Navigate /
  IndexPage->>Stories: Render static stories slider
  IndexPage->>Reco: Render static recommended slider
  IndexPage->>MenuStore: Read menu?.categories
  IndexPage->>CatMenu: Render categories slider (categories)
  loop For each category
    IndexPage->>CatBlock: Render with categoryId
    CatBlock->>MenuStore: Get category by id
    CatBlock->>CatBlock: Filter purchasable products with variants
    loop For each product
      CatBlock->>ProductCard: Render product card
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • chore: navigation rework #122 — Adjusts placement of the tg-safe-area class in app root attributes; directly related to this PR’s movement of tg-safe-area from nuxt.config to the layout.

Poem

A hop, a skip, I slide the lanes,
New cards and tales in scrolling trains.
Categories glide, recommendations gleam,
Points on a card—what a tasty theme!
Safe-area snug, UI just right—
I twitch my nose, then browse all night. 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sliders

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Sep 2, 2025

@hmbanan666 hmbanan666 merged commit 2588435 into main Sep 2, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the sliders branch September 2, 2025 13:41
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (15)
apps/storefront-telegram/app/components/catalog/StoriesSlider.vue (3)

3-3: Prevent wrapping in horizontal slider

Use flex-nowrap to avoid wrapping rows inside a horizontally scrolling container.

-    <div class="w-max flex flex-row flex-wrap gap-2">
+    <div class="w-max flex flex-row flex-nowrap gap-2">

2-2: Stronger scroll snapping

Consider snap-mandatory (or snap-proximity) for a crisper snap behavior.

-  <div class="max-w-full overflow-x-scroll snap-x">
+  <div class="max-w-full overflow-x-scroll snap-x snap-mandatory">

3-3: Basic a11y semantics for a slider list

Add list/listitem roles and labels; make items focusable for keyboard users.

-    <div class="w-max flex flex-row flex-wrap gap-2">
+    <div class="w-max flex flex-row flex-nowrap gap-2" role="list" aria-label="Истории">
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">
@@
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">
@@
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">
@@
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">
@@
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">
@@
-      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg">
+      <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-2/3 rounded-lg" role="listitem" tabindex="0">

Also applies to: 4-4, 10-10, 14-14, 18-18, 22-22, 26-26

apps/storefront-telegram/app/pages/user.vue (1)

5-11: Replace placeholder copy or gate behind feature flag

"Тут будет меню" reads like a placeholder; consider i18n or hide until ready.

-        <h2 class="text-lg/5 font-bold">
-          Тут будет меню
-        </h2>
+        <h2 class="text-lg/5 font-bold">
+          {{ $t('user.menu.soon') }}
+        </h2>
apps/storefront-telegram/app/components/UserPointsCard.vue (2)

7-9: Make percentage dynamic (prop) instead of hard-coded 5%

Allows reuse and future wiring to backend/store without touching markup.

-      <div class="text-3xl/5 font-bold">
-        5%
-      </div>
+      <div class="text-3xl/5 font-bold" aria-label="Скидка пользователя">
+        {{ percent }}%
+      </div>

Add in <script setup>:

-const clientStore = useClientStore()
+const clientStore = useClientStore()
+const props = withDefaults(defineProps<{ percent?: number }>(), { percent: 5 })
+const percent = computed(() => props.percent)

4-6: Name fallback to avoid blank UI

Guard against empty fullName to keep layout stable.

-      <div class="text-lg/5 font-semibold">
-        {{ clientStore.fullName }}
-      </div>
+      <div class="text-lg/5 font-semibold">
+        {{ clientStore.fullName || 'Гость' }}
+      </div>
apps/storefront-telegram/app/components/CitySelector.vue (2)

26-29: Unify checkbox group UI config via constant

Keeps template lean and avoids reactive churn.

-          :ui="{
-            item: 'items-center',
-            label: '!text-lg',
-          }"
+          :ui="checkboxGroupUi"

Add in <script setup>:

const checkboxGroupUi = {
  item: 'items-center',
  label: '!text-lg',
}

8-11: Factor UI config constant; test overlay padding

  • Move the inline ui object in CitySelector.vue to a top-level constant in <script setup> to prevent it being re-created each render (e.g.
    -    :ui="{
    -      content: 'max-h-10/12 !mt-150',
    -      overlay: 'tg-content-safe-area-top',
    -    }"
    +    :ui="drawerUi"
    and
    const drawerUi = {
      content: 'max-h-10/12 !mt-150',
      overlay: 'tg-content-safe-area-top',
    }
  • Verified that .tg-safe-area is applied in default.vue and .tg-content-safe-area-top is defined in styles.css; manually test the drawer overlay to ensure it isn’t double-padded under the layout’s safe-area wrapper.
apps/storefront-telegram/app/pages/index.vue (1)

15-19: Guard v-for source to avoid undefined during initial load.
If menu is still loading, v-for over undefined can warn; coalesce to an empty array.

Apply:

-    <CatalogCategoryBlock
-      v-for="category in menuStore.menu?.categories"
+    <CatalogCategoryBlock
+      v-for="category in (menuStore.menu?.categories ?? [])"
       :key="category.id"
       :category-id="category.id"
     />
apps/storefront-telegram/app/components/catalog/CategoryBlock.vue (2)

19-21: Loosen prop type to match id shape from store.
If category.id is numeric, the strict string prop will be awkward.

-const { categoryId } = defineProps<{
-  categoryId: string
-}>()
+const { categoryId } = defineProps<{
+  categoryId: string | number
+}>()

2-2: Add anchors and scroll offset; hide empty sections.
Enables in-page navigation from the categories slider and avoids rendering empty blocks.

-  <div class="flex flex-col gap-3 mb-10">
+  <div
+    :id="`category-${categoryId}`"
+    class="flex flex-col gap-3 mb-10 scroll-mt-20"
+    v-if="products.length"
+  >
apps/storefront-telegram/app/components/catalog/RecommendedSlider.vue (2)

9-61: DRY: generate items with v-for instead of duplicating markup.
Cuts maintenance and DOM size.

-      <div class="w-max flex flex-row flex-wrap gap-2">
-        <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-3/4 rounded-lg">
-          <div class="p-2 max-w-24">
-            1 товар
-          </div>
-        </div>
-        ...
-        <div class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-3/4 rounded-lg">
-          <div class="p-2 max-w-24">
-            9 товар
-          </div>
-        </div>
-      </div>
+      <div class="w-max flex flex-row gap-2">
+        <div
+          v-for="n in 9"
+          :key="n"
+          class="min-w-24 scroll-ml-6 snap-start border border-primary aspect-3/4 rounded-lg"
+        >
+          <div class="p-2 max-w-24">
+            {{ n }} товар
+          </div>
+        </div>
+      </div>

7-9: Slider ergonomics: single row + stronger snapping.
Avoid wrapping and enable mandatory snapping.

-    <div class="max-w-full overflow-x-scroll snap-x">
-      <div class="w-max flex flex-row flex-wrap gap-2">
+    <div class="max-w-full overflow-x-auto snap-x snap-mandatory">
+      <div class="w-max flex flex-row gap-2">
apps/storefront-telegram/app/components/catalog/CategoriesSliderMenu.vue (2)

5-13: Make categories clickable and navigate to sections.
Anchor to the corresponding CategoryBlock ids.

-        <div
-          v-for="category in menuStore.menu?.categories"
-          :key="category.id"
-          class="scroll-ml-6 snap-start"
-        >
-          <div class="p-0">
-            {{ category.name }}
-          </div>
-        </div>
+        <div
+          v-for="category in menuStore.menu?.categories"
+          :key="category.id"
+          class="scroll-ml-6 snap-start"
+        >
+          <a
+            :href="`#category-${category.id}`"
+            class="inline-block px-3 py-2 rounded-full border border-transparent hover:border-primary transition"
+          >
+            {{ category.name }}
+          </a>
+        </div>

3-5: Slider behavior: prevent wrap and enable mandatory snapping.
Produces a true horizontal slider.

-    <div class="max-w-full overflow-x-scroll snap-x">
-      <div class="w-max flex flex-row flex-wrap gap-5">
+    <div class="max-w-full overflow-x-auto snap-x snap-mandatory">
+      <div class="w-max flex flex-row gap-5">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 97bc41b and 93cedf7.

📒 Files selected for processing (11)
  • apps/storefront-telegram/app/components/CategoryBlock.vue (0 hunks)
  • apps/storefront-telegram/app/components/CitySelector.vue (2 hunks)
  • apps/storefront-telegram/app/components/UserPointsCard.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/CategoriesSliderMenu.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/CategoryBlock.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/RecommendedSlider.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/StoriesSlider.vue (1 hunks)
  • apps/storefront-telegram/app/layouts/default.vue (1 hunks)
  • apps/storefront-telegram/app/pages/index.vue (1 hunks)
  • apps/storefront-telegram/app/pages/user.vue (1 hunks)
  • apps/storefront-telegram/nuxt.config.ts (0 hunks)
💤 Files with no reviewable changes (2)
  • apps/storefront-telegram/nuxt.config.ts
  • apps/storefront-telegram/app/components/CategoryBlock.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (5)
apps/storefront-telegram/app/layouts/default.vue (1)

2-2: Safe-area class only on <main> and removed from rootAttrs – Confirmed no tg-safe-area in nuxt.config.ts app.rootAttrs; only applied on layouts/default.vue::main.

apps/storefront-telegram/app/pages/user.vue (1)

3-3: Component inclusion looks good

UserPointsCard placement in PageContainer is straightforward.

apps/storefront-telegram/app/pages/index.vue (1)

10-14: LGTM: new sliders composition fits the home flow.
No issues spotted with the new CatalogStoriesSlider and CatalogRecommendedSlider mounts.

apps/storefront-telegram/app/components/catalog/RecommendedSlider.vue (1)

9-61: Confirm CSS utility support (aspect-3/4, min-w-24, max-w-24, etc.)
No Tailwind or UnoCSS config found in the repo—verify your CSS engine defines these classes (and related ones like scroll-ml-6, snap-start, border-primary) via UnoCSS presets or Tailwind theme/plugins.

apps/storefront-telegram/app/components/catalog/CategoriesSliderMenu.vue (1)

2-2: Confirm custom utilities exist
Could not locate h-18 or bg-primary in your CSS configuration; please verify these classes are defined in your UnoCSS/Tailwind setup.

Comment on lines +23 to +26
const menuStore = useMenuStore()
const category = menuStore.menu?.categories.find((c) => c.id === categoryId)
const products = category?.products.filter((p) => p.isAvailableForPurchase && p.variants.length)
</script>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix non-reactive lookups; block won’t update after menu loads.
category/products are computed once; they won’t react to menuStore.menu changes. Also missing optional chaining on categories, and variants.length can throw if variants is undefined.

Use computed + safe checks:

-const menuStore = useMenuStore()
-const category = menuStore.menu?.categories.find((c) => c.id === categoryId)
-const products = category?.products.filter((p) => p.isAvailableForPurchase && p.variants.length)
+const menuStore = useMenuStore()
+const category = computed(() =>
+  menuStore.menu?.categories?.find((c) => String(c.id) === String(categoryId))
+)
+const products = computed(() =>
+  category.value?.products?.filter(
+    (p) => p.isAvailableForPurchase && (p.variants?.length ?? 0) > 0
+  ) ?? []
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const menuStore = useMenuStore()
const category = menuStore.menu?.categories.find((c) => c.id === categoryId)
const products = category?.products.filter((p) => p.isAvailableForPurchase && p.variants.length)
</script>
const menuStore = useMenuStore()
const category = computed(() =>
menuStore.menu?.categories?.find((c) => String(c.id) === String(categoryId))
)
const products = computed(() =>
category.value?.products?.filter(
(p) => p.isAvailableForPurchase && (p.variants?.length ?? 0) > 0
) ?? []
)
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant