diff --git a/app/resources/js/composables/useLayoutTier.ts b/app/resources/js/composables/useLayoutTier.ts new file mode 100644 index 00000000..f99c6efd --- /dev/null +++ b/app/resources/js/composables/useLayoutTier.ts @@ -0,0 +1,31 @@ +import { computed, type ComputedRef } from 'vue'; +import { useDisplay } from 'vuetify'; + +export type LayoutTier = 'phone' | 'tablet' | 'desktop'; + +/** + * Единый источник «яруса» экрана для адаптива портала. + * phone < 600px (нижнее меню-вкладки) + * tablet 600..1279px (узкая колонка-иконки / rail) + * desktop >= 1280px (полный сайдбар 232px, как сейчас) + */ +export function useLayoutTier(): { + tier: ComputedRef; + isPhone: ComputedRef; + isTablet: ComputedRef; + isDesktop: ComputedRef; +} { + const display = useDisplay(); + const tier = computed(() => { + const w = display.width.value; + if (w < 600) return 'phone'; + if (w < 1280) return 'tablet'; + return 'desktop'; + }); + return { + tier, + isPhone: computed(() => tier.value === 'phone'), + isTablet: computed(() => tier.value === 'tablet'), + isDesktop: computed(() => tier.value === 'desktop'), + }; +} diff --git a/app/tests/Frontend/useLayoutTier.spec.ts b/app/tests/Frontend/useLayoutTier.spec.ts new file mode 100644 index 00000000..e219dd17 --- /dev/null +++ b/app/tests/Frontend/useLayoutTier.spec.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from 'vitest'; +import { defineComponent } from 'vue'; +import { mount } from '@vue/test-utils'; +import { createVuetify } from 'vuetify'; +import { useLayoutTier } from '../../resources/js/composables/useLayoutTier'; + +function tierAtWidth(width: number): string { + Object.defineProperty(window, 'innerWidth', { configurable: true, value: width }); + window.dispatchEvent(new Event('resize')); + const vuetify = createVuetify(); + let captured = ''; + const Harness = defineComponent({ + setup() { + const { tier } = useLayoutTier(); + captured = tier.value; + return () => null; + }, + }); + mount(Harness, { global: { plugins: [vuetify] } }); + return captured; +} + +describe('useLayoutTier', () => { + it('телефон при ширине < 600', () => { expect(tierAtWidth(390)).toBe('phone'); }); + it('планшет при 600..1279', () => { expect(tierAtWidth(820)).toBe('tablet'); }); + it('десктоп при >= 1280', () => { expect(tierAtWidth(1440)).toBe('desktop'); }); +});