@cavulsqa/create 2.9.3 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/bin/create.mjs +18 -25
- package/lib/templates.mjs +56 -0
- package/package.json +13 -5
- package/templates/f7-app/auto-imports.d.ts +9 -0
- package/templates/f7-app/package.json +6 -3
- package/templates/f7-app/src/env.d.ts +1 -0
- package/templates/f7-app/src/main.ts +3 -0
- package/templates/f7-app/src/plugins/bootstrapError.ts +2 -0
- package/templates/f7-app/src/plugins/recorder.plugin.ts +155 -0
- package/templates/f7-app/src/shared/recorder/capacitorSink.ts +124 -0
- package/templates/f7-app/vite.config.ts +1 -0
- package/templates/m3e-app/.claude/rules/data-fetching.md +68 -0
- package/templates/m3e-app/.claude/rules/database.md +106 -0
- package/templates/m3e-app/.claude/rules/m3e-ui.md +48 -0
- package/templates/m3e-app/.claude/rules/modules.md +43 -0
- package/templates/m3e-app/.claude/rules/native.md +60 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/SKILL.md +68 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/color.md +44 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/components.md +325 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/layout.md +42 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/motion.md +51 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/shapes-type.md +48 -0
- package/templates/m3e-app/.claude/skills/m3-expressive/sources.md +53 -0
- package/templates/m3e-app/.claude/skills/module-architecture/SKILL.md +65 -0
- package/templates/m3e-app/.claude/skills/module-architecture/file-templates.md +178 -0
- package/templates/m3e-app/.claude/skills/reactive-data/SKILL.md +90 -0
- package/templates/m3e-app/.claude/skills/reactive-data/testing.md +55 -0
- package/templates/m3e-app/.env.example +32 -0
- package/templates/m3e-app/CLAUDE.md +93 -0
- package/templates/m3e-app/auto-imports.d.ts +851 -0
- package/templates/m3e-app/capacitor.config.ts +44 -0
- package/templates/m3e-app/components.d.ts +252 -0
- package/templates/m3e-app/index.html +16 -0
- package/templates/m3e-app/package.json +108 -0
- package/templates/m3e-app/src/App.vue +129 -0
- package/templates/m3e-app/src/app/pragmas.config.ts +35 -0
- package/templates/m3e-app/src/app/scroll.config.ts +20 -0
- package/templates/m3e-app/src/app/storage.config.ts +65 -0
- package/templates/m3e-app/src/app/tabs.ts +33 -0
- package/templates/m3e-app/src/app/theme.config.ts +51 -0
- package/templates/m3e-app/src/assets/css/app.css +18 -0
- package/templates/m3e-app/src/assets/css/base.css +53 -0
- package/templates/m3e-app/src/assets/css/layout/container-transform.css +113 -0
- package/templates/m3e-app/src/assets/css/layout/shell.css +69 -0
- package/templates/m3e-app/src/assets/css/layout/transitions.css +121 -0
- package/templates/m3e-app/src/assets/css/m3e.css +6 -0
- package/templates/m3e-app/src/assets/css/theme/framework7.css +18 -0
- package/templates/m3e-app/src/assets/css/theme/tailwind.css +365 -0
- package/templates/m3e-app/src/domains/benchmark/benchmark.dataset.ts +209 -0
- package/templates/m3e-app/src/domains/benchmark/benchmark.suite.ts +662 -0
- package/templates/m3e-app/src/domains/sales/sales.repository.ts +458 -0
- package/templates/m3e-app/src/env.d.ts +40 -0
- package/templates/m3e-app/src/locales/ar.json +1260 -0
- package/templates/m3e-app/src/locales/en.json +1260 -0
- package/templates/m3e-app/src/locales/fr.json +1260 -0
- package/templates/m3e-app/src/main.ts +41 -0
- package/templates/m3e-app/src/modules/demo/components/DemoBenchmark.vue +119 -0
- package/templates/m3e-app/src/modules/demo/components/DemoBusLog.vue +63 -0
- package/templates/m3e-app/src/modules/demo/components/DemoCreateOrderSheet.vue +203 -0
- package/templates/m3e-app/src/modules/demo/components/DemoMetricsSheet.vue +75 -0
- package/templates/m3e-app/src/modules/demo/components/DemoOrderList.vue +75 -0
- package/templates/m3e-app/src/modules/demo/components/DemoPipelineBenchmark.vue +65 -0
- package/templates/m3e-app/src/modules/demo/components/DemoStatCards.vue +71 -0
- package/templates/m3e-app/src/modules/demo/composables/useBenchmark.ts +139 -0
- package/templates/m3e-app/src/modules/demo/composables/useOrderStatus.ts +64 -0
- package/templates/m3e-app/src/modules/demo/composables/useReactiveDemo.ts +171 -0
- package/templates/m3e-app/src/modules/demo/router/routes/demo.routes.ts +22 -0
- package/templates/m3e-app/src/modules/demo/views/DemoView.vue +210 -0
- package/templates/m3e-app/src/modules/demo/views/OrderDetailView.vue +136 -0
- package/templates/m3e-app/src/modules/demo/views/OrderSearchView.vue +74 -0
- package/templates/m3e-app/src/modules/gallery/components/GalleryBlock.vue +16 -0
- package/templates/m3e-app/src/modules/gallery/components/GalleryCarouselTile.vue +71 -0
- package/templates/m3e-app/src/modules/gallery/components/GalleryCustomerForm.vue +76 -0
- package/templates/m3e-app/src/modules/gallery/components/GalleryProofOfDelivery.vue +69 -0
- package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaDay.vue +106 -0
- package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaMonth.vue +40 -0
- package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaVisitList.vue +45 -0
- package/templates/m3e-app/src/modules/gallery/components/chat/ChatAttachSheet.vue +106 -0
- package/templates/m3e-app/src/modules/gallery/components/chat/ChatContactPicker.vue +85 -0
- package/templates/m3e-app/src/modules/gallery/components/chat/ChatInviteComposer.vue +131 -0
- package/templates/m3e-app/src/modules/gallery/components/chat/ChatPollComposer.vue +148 -0
- package/templates/m3e-app/src/modules/gallery/components/chat/ChatRecentPhotos.vue +62 -0
- package/templates/m3e-app/src/modules/gallery/components/inputs/InputsAccount.vue +79 -0
- package/templates/m3e-app/src/modules/gallery/components/inputs/InputsTags.vue +53 -0
- package/templates/m3e-app/src/modules/gallery/components/inputs/InputsVerification.vue +73 -0
- package/templates/m3e-app/src/modules/gallery/components/inputs/PasswordStrength.vue +37 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryButtons.vue +128 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCarousels.vue +236 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCharts.vue +84 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryFabs.vue +70 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryInputs.vue +219 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryNavigation.vue +141 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryOverlays.vue +368 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryPickers.vue +175 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryProgress.vue +118 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryScale.vue +103 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GallerySelection.vue +219 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryShapes.vue +48 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GallerySurfaces.vue +213 -0
- package/templates/m3e-app/src/modules/gallery/components/sections/GalleryTables.vue +185 -0
- package/templates/m3e-app/src/modules/gallery/components/surfaces/SurfacesContainerTransform.vue +46 -0
- package/templates/m3e-app/src/modules/gallery/composables/chatTeam.ts +18 -0
- package/templates/m3e-app/src/modules/gallery/composables/composeKind.ts +2 -0
- package/templates/m3e-app/src/modules/gallery/composables/currentPosition.ts +35 -0
- package/templates/m3e-app/src/modules/gallery/composables/demoOrders.ts +29 -0
- package/templates/m3e-app/src/modules/gallery/composables/featuredStories.ts +73 -0
- package/templates/m3e-app/src/modules/gallery/composables/fieldFormats.ts +36 -0
- package/templates/m3e-app/src/modules/gallery/composables/openExternal.ts +11 -0
- package/templates/m3e-app/src/modules/gallery/composables/routePlan.ts +90 -0
- package/templates/m3e-app/src/modules/gallery/composables/useAgenda.ts +61 -0
- package/templates/m3e-app/src/modules/gallery/composables/useChatCustomers.ts +31 -0
- package/templates/m3e-app/src/modules/gallery/composables/useChatDemo.ts +299 -0
- package/templates/m3e-app/src/modules/gallery/composables/useGallerySections.ts +230 -0
- package/templates/m3e-app/src/modules/gallery/composables/useLocalAttachments.ts +71 -0
- package/templates/m3e-app/src/modules/gallery/composables/useLocationShare.ts +38 -0
- package/templates/m3e-app/src/modules/gallery/composables/usePhotoScenes.ts +82 -0
- package/templates/m3e-app/src/modules/gallery/composables/useTreeDemo.ts +67 -0
- package/templates/m3e-app/src/modules/gallery/composables/wilayas.ts +67 -0
- package/templates/m3e-app/src/modules/gallery/router/routes/gallery.routes.ts +52 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryAgendaView.vue +117 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryChatView.vue +292 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryContactsView.vue +77 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryFeaturedView.vue +60 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryLoginView.vue +135 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryOnboardingView.vue +116 -0
- package/templates/m3e-app/src/modules/gallery/views/GallerySectionView.vue +27 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryTabsView.vue +135 -0
- package/templates/m3e-app/src/modules/gallery/views/GalleryView.vue +50 -0
- package/templates/m3e-app/src/modules/home/components/HomeHero.vue +57 -0
- package/templates/m3e-app/src/modules/home/composables/useHomeFeatures.ts +128 -0
- package/templates/m3e-app/src/modules/home/composables/useOpenFeature.ts +22 -0
- package/templates/m3e-app/src/modules/home/router/routes/home.routes.ts +21 -0
- package/templates/m3e-app/src/modules/home/views/FeatureDetailView.vue +66 -0
- package/templates/m3e-app/src/modules/home/views/HomeView.vue +47 -0
- package/templates/m3e-app/src/modules/settings/components/RolePalette.vue +38 -0
- package/templates/m3e-app/src/modules/settings/components/SeedSwatches.vue +41 -0
- package/templates/m3e-app/src/modules/settings/components/SettingsChoice.vue +43 -0
- package/templates/m3e-app/src/modules/settings/components/StudioPreview.vue +52 -0
- package/templates/m3e-app/src/modules/settings/router/routes/settings.routes.ts +17 -0
- package/templates/m3e-app/src/modules/settings/types.ts +7 -0
- package/templates/m3e-app/src/modules/settings/views/ColorStudioView.vue +166 -0
- package/templates/m3e-app/src/modules/settings/views/SettingsView.vue +157 -0
- package/templates/m3e-app/src/plugins/bootstrapError.ts +62 -0
- package/templates/m3e-app/src/plugins/capacitor/index.ts +14 -0
- package/templates/m3e-app/src/plugins/capacitor/useAndroidBackButton.ts +36 -0
- package/templates/m3e-app/src/plugins/capacitor/useKeyboard.ts +48 -0
- package/templates/m3e-app/src/plugins/capacitor/useSplashScreen.ts +43 -0
- package/templates/m3e-app/src/plugins/capacitor/useStatusBar.ts +16 -0
- package/templates/m3e-app/src/plugins/framework7.plugin.ts +36 -0
- package/templates/m3e-app/src/plugins/i18n.plugin.ts +87 -0
- package/templates/m3e-app/src/plugins/m3e.plugin.ts +22 -0
- package/templates/m3e-app/src/plugins/seed.plugin.ts +7 -0
- package/templates/m3e-app/src/plugins/sqlite.plugin.ts +32 -0
- package/templates/m3e-app/src/router/global/global.routes.ts +12 -0
- package/templates/m3e-app/src/router/index.ts +20 -0
- package/templates/m3e-app/src/shared/components/error/404.vue +13 -0
- package/templates/m3e-app/src/shared/components/layout/EmptyState.vue +30 -0
- package/templates/m3e-app/src/shared/components/layout/SectionHeader.vue +10 -0
- package/templates/m3e-app/src/shared/components/page/AppPage.vue +104 -0
- package/templates/m3e-app/src/shared/composables/navigation/useActiveTab.ts +39 -0
- package/templates/m3e-app/src/shared/composables/navigation/useContainerTransform.ts +117 -0
- package/templates/m3e-app/src/shared/composables/navigation/useNavigationGuard.ts +48 -0
- package/templates/m3e-app/src/shared/composables/navigation/useNavigationVisibility.ts +64 -0
- package/templates/m3e-app/src/shared/composables/navigation/useViewRouter.ts +25 -0
- package/templates/m3e-app/src/shared/composables/navigation/useWindowClass.ts +22 -0
- package/templates/m3e-app/src/shared/composables/theme/useThemeSettings.ts +155 -0
- package/templates/m3e-app/src/shared/database/candidates/capacitorSqlite.ts +36 -0
- package/templates/m3e-app/src/shared/database/candidates/index.ts +4 -0
- package/templates/m3e-app/src/shared/database/candidates/opfsSahPool.ts +25 -0
- package/templates/m3e-app/src/shared/database/candidates/types.ts +56 -0
- package/templates/m3e-app/src/shared/database/candidates/waSqlite.ts +56 -0
- package/templates/m3e-app/src/shared/database/database.ts +219 -0
- package/templates/m3e-app/src/shared/database/index.ts +3 -0
- package/templates/m3e-app/src/shared/database/migrations.ts +223 -0
- package/templates/m3e-app/src/shared/database/opfs.worker.ts +5 -0
- package/templates/m3e-app/src/shared/database/queries.ts +26 -0
- package/templates/m3e-app/src/shared/database/schema.ts +153 -0
- package/templates/m3e-app/src/shared/database/storage.ts +64 -0
- package/templates/m3e-app/src/shared/database/wa.worker.ts +5 -0
- package/templates/m3e-app/src/shared/utils/lazyRoute.ts +41 -0
- package/templates/m3e-app/src/shared/utils/resolvers/resolvers.ts +42 -0
- package/templates/m3e-app/src/shared/utils/textDirection.ts +22 -0
- package/templates/m3e-app/src/shared/utils/theme/themeSettings.ts +59 -0
- package/templates/m3e-app/src/shared/utils/tone.ts +8 -0
- package/templates/m3e-app/tests/benchmark.suite.test.ts +104 -0
- package/templates/m3e-app/tests/containerTransform.test.ts +58 -0
- package/templates/m3e-app/tests/fieldFormats.test.ts +25 -0
- package/templates/m3e-app/tests/lazyRoute.test.ts +30 -0
- package/templates/m3e-app/tests/locales.test.ts +73 -0
- package/templates/m3e-app/tests/migrations.test.ts +74 -0
- package/templates/m3e-app/tests/navigationGuard.test.ts +82 -0
- package/templates/m3e-app/tests/openDatabase.test.ts +54 -0
- package/templates/m3e-app/tests/sales.repository.test.ts +329 -0
- package/templates/m3e-app/tests/storage.test.ts +117 -0
- package/templates/m3e-app/tests/textDirection.test.ts +11 -0
- package/templates/m3e-app/tooling/linkedPackages.ts +112 -0
- package/templates/m3e-app/tsconfig.json +21 -0
- package/templates/m3e-app/vite.config.ts +144 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<M3PullToRefresh :refresh="refresh" :label="t('gallery.scale.refreshing')" />
|
|
3
|
+
|
|
4
|
+
<GalleryBlock
|
|
5
|
+
:title="t('gallery.scale.virtual')"
|
|
6
|
+
:note="t('gallery.scale.virtualNote', { count: rows.length })"
|
|
7
|
+
>
|
|
8
|
+
<M3Chip :label="t('gallery.scale.rendered', { count: rendered }, rendered)">
|
|
9
|
+
<template #icon><i-ms-speed-rounded /></template>
|
|
10
|
+
</M3Chip>
|
|
11
|
+
<M3Chip :label="t('gallery.scale.refreshed', { count: refreshes })">
|
|
12
|
+
<template #icon><i-ms-refresh-rounded /></template>
|
|
13
|
+
</M3Chip>
|
|
14
|
+
</GalleryBlock>
|
|
15
|
+
|
|
16
|
+
<div class="h-3" />
|
|
17
|
+
<M3VirtualList
|
|
18
|
+
ref="list"
|
|
19
|
+
:items="rows"
|
|
20
|
+
:item-size="74"
|
|
21
|
+
:item-key="(row) => row.id"
|
|
22
|
+
inset
|
|
23
|
+
:label="t('gallery.scale.virtual')"
|
|
24
|
+
>
|
|
25
|
+
<template #default="{ item }">
|
|
26
|
+
<M3ListItem
|
|
27
|
+
as="div"
|
|
28
|
+
clickable
|
|
29
|
+
:headline="item.title"
|
|
30
|
+
:supporting="item.subtitle"
|
|
31
|
+
:trailing-text="item.amount"
|
|
32
|
+
>
|
|
33
|
+
<template #leading>
|
|
34
|
+
<M3Shape :shape="item.shape" class="size-10" :class="TONE_CLASSES[item.tone]">
|
|
35
|
+
<span class="type-label-large">{{ item.initials }}</span>
|
|
36
|
+
</M3Shape>
|
|
37
|
+
</template>
|
|
38
|
+
</M3ListItem>
|
|
39
|
+
</template>
|
|
40
|
+
</M3VirtualList>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup lang="ts">
|
|
44
|
+
import type { MaterialShapeName } from "@cavulsqa/m3e";
|
|
45
|
+
import type { ComponentPublicInstance } from "vue";
|
|
46
|
+
import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
|
|
47
|
+
import { TONE_CLASSES, type Tone } from "@/shared/utils/tone";
|
|
48
|
+
|
|
49
|
+
const { t } = useI18n();
|
|
50
|
+
const snackbar = useSnackbar();
|
|
51
|
+
|
|
52
|
+
const SHAPES: readonly MaterialShapeName[] = [
|
|
53
|
+
"cookie9Sided",
|
|
54
|
+
"clover4Leaf",
|
|
55
|
+
"pentagon",
|
|
56
|
+
"sunny",
|
|
57
|
+
"gem",
|
|
58
|
+
];
|
|
59
|
+
const TONES: readonly Tone[] = ["primary", "secondary", "tertiary"];
|
|
60
|
+
const CITIES = ["Alger", "Oran", "Constantine", "Annaba", "Blida", "Sétif", "Tlemcen", "Béjaïa"];
|
|
61
|
+
const COUNT = 5000;
|
|
62
|
+
const formatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 0 });
|
|
63
|
+
|
|
64
|
+
const refreshes = ref(0);
|
|
65
|
+
const rows = shallowRef(build(0));
|
|
66
|
+
|
|
67
|
+
function build(seed: number) {
|
|
68
|
+
return Array.from({ length: COUNT }, (_, index) => {
|
|
69
|
+
const n = (index * 7919 + seed * 104729) % 100000;
|
|
70
|
+
const city = CITIES[n % CITIES.length]!;
|
|
71
|
+
return {
|
|
72
|
+
id: index,
|
|
73
|
+
title: `${t("gallery.scale.customer")} ${String(index + 1).padStart(4, "0")}`,
|
|
74
|
+
subtitle: `${city} · ${t("gallery.scale.orders", { count: (n % 40) + 1 }, (n % 40) + 1)}`,
|
|
75
|
+
amount: formatter.format((n % 9000) + 100),
|
|
76
|
+
initials: city.slice(0, 2).toUpperCase(),
|
|
77
|
+
shape: SHAPES[index % SHAPES.length]!,
|
|
78
|
+
tone: TONES[index % TONES.length]!,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** How many rows are actually in the DOM - the number that proves virtualisation works. */
|
|
84
|
+
const list = useTemplateRef<ComponentPublicInstance>("list");
|
|
85
|
+
const rendered = ref(0);
|
|
86
|
+
let observer: MutationObserver | null = null;
|
|
87
|
+
onMounted(() => {
|
|
88
|
+
const element = list.value?.$el as HTMLElement | undefined;
|
|
89
|
+
if (!element) return;
|
|
90
|
+
const count = () => (rendered.value = element.childElementCount);
|
|
91
|
+
count();
|
|
92
|
+
observer = new MutationObserver(count);
|
|
93
|
+
observer.observe(element, { childList: true });
|
|
94
|
+
});
|
|
95
|
+
onBeforeUnmount(() => observer?.disconnect());
|
|
96
|
+
|
|
97
|
+
async function refresh() {
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 1400));
|
|
99
|
+
refreshes.value += 1;
|
|
100
|
+
rows.value = build(refreshes.value);
|
|
101
|
+
void snackbar.show(t("gallery.scale.updated"));
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<GalleryBlock
|
|
3
|
+
:title="t('gallery.selection.switches')"
|
|
4
|
+
:note="t('gallery.selection.switchesNote')"
|
|
5
|
+
>
|
|
6
|
+
<M3Switch v-model="wifi" :label="t('gallery.selection.wifi')" />
|
|
7
|
+
<M3Switch v-model="bluetooth" icons :label="t('gallery.selection.bluetooth')" />
|
|
8
|
+
<M3Switch v-model="airplane" both-icons :label="t('gallery.selection.airplane')" />
|
|
9
|
+
<M3Switch :model-value="true" disabled :label="t('gallery.selection.locked')" />
|
|
10
|
+
</GalleryBlock>
|
|
11
|
+
|
|
12
|
+
<GalleryBlock
|
|
13
|
+
:title="t('gallery.selection.stepper')"
|
|
14
|
+
:note="t('gallery.selection.stepperNote')"
|
|
15
|
+
stack
|
|
16
|
+
>
|
|
17
|
+
<div class="flex items-center justify-between gap-4">
|
|
18
|
+
<span class="type-body-large text-on-surface">{{ t("gallery.selection.guests") }}</span>
|
|
19
|
+
<M3Stepper
|
|
20
|
+
v-model="guests"
|
|
21
|
+
:label="t('gallery.selection.guests')"
|
|
22
|
+
:min="1"
|
|
23
|
+
:max="12"
|
|
24
|
+
:decrement-label="t('gallery.selection.decrease')"
|
|
25
|
+
:increment-label="t('gallery.selection.increase')"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="flex items-center justify-between gap-4">
|
|
29
|
+
<span class="type-body-large text-on-surface">{{ t("gallery.selection.weight") }}</span>
|
|
30
|
+
<M3Stepper
|
|
31
|
+
v-model="weight"
|
|
32
|
+
variant="tonal"
|
|
33
|
+
editable
|
|
34
|
+
:label="t('gallery.selection.weight')"
|
|
35
|
+
:min="0"
|
|
36
|
+
:max="50"
|
|
37
|
+
:step="0.5"
|
|
38
|
+
:format="(value) => t('gallery.selection.kilos', { value: value.toFixed(1) })"
|
|
39
|
+
:decrement-label="t('gallery.selection.decrease')"
|
|
40
|
+
:increment-label="t('gallery.selection.increase')"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="flex items-center justify-between gap-4">
|
|
44
|
+
<span class="type-body-large text-on-surface">{{ t("gallery.selection.units") }}</span>
|
|
45
|
+
<M3Stepper
|
|
46
|
+
v-model="units"
|
|
47
|
+
size="m"
|
|
48
|
+
editable
|
|
49
|
+
:label="t('gallery.selection.units')"
|
|
50
|
+
:min="0"
|
|
51
|
+
:max="1000"
|
|
52
|
+
:decrement-label="t('gallery.selection.decrease')"
|
|
53
|
+
:increment-label="t('gallery.selection.increase')"
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
</GalleryBlock>
|
|
57
|
+
|
|
58
|
+
<GalleryBlock
|
|
59
|
+
:title="t('gallery.selection.smart')"
|
|
60
|
+
:note="t('gallery.selection.smartNote')"
|
|
61
|
+
stack
|
|
62
|
+
>
|
|
63
|
+
<M3List variant="segmented" class="-mx-1">
|
|
64
|
+
<M3SmartSelect
|
|
65
|
+
v-model="deliveryDays"
|
|
66
|
+
multiple
|
|
67
|
+
:label="t('gallery.selection.deliveryDays')"
|
|
68
|
+
:options="dayOptions"
|
|
69
|
+
:placeholder="t('gallery.selection.none')"
|
|
70
|
+
:done-label="t('gallery.selection.done')"
|
|
71
|
+
>
|
|
72
|
+
<template #leading><i-ms-calendar-month-outline-rounded /></template>
|
|
73
|
+
</M3SmartSelect>
|
|
74
|
+
<M3SmartSelect
|
|
75
|
+
v-model="zone"
|
|
76
|
+
:label="t('gallery.inputs.wilaya')"
|
|
77
|
+
:options="WILAYA_OPTIONS"
|
|
78
|
+
:placeholder="t('gallery.selection.none')"
|
|
79
|
+
:search-placeholder="t('gallery.selection.searchWilaya')"
|
|
80
|
+
:no-results-text="t('gallery.inputs.noMatches')"
|
|
81
|
+
>
|
|
82
|
+
<template #leading><i-ms-location-on-outline-rounded /></template>
|
|
83
|
+
</M3SmartSelect>
|
|
84
|
+
</M3List>
|
|
85
|
+
</GalleryBlock>
|
|
86
|
+
|
|
87
|
+
<GalleryBlock :title="t('gallery.selection.checks')" :note="t('gallery.selection.checksNote')">
|
|
88
|
+
<M3Checkbox v-model="terms" :label="t('gallery.selection.terms')" />
|
|
89
|
+
<M3Checkbox :model-value="false" indeterminate :label="t('gallery.selection.partial')" />
|
|
90
|
+
<M3Checkbox v-model="invalid" error :label="t('gallery.selection.required')" />
|
|
91
|
+
<span class="mx-2 h-8 w-px bg-outline-variant" />
|
|
92
|
+
<M3Radio
|
|
93
|
+
v-for="size in SIZES"
|
|
94
|
+
:key="size"
|
|
95
|
+
v-model="cup"
|
|
96
|
+
:value="size"
|
|
97
|
+
:label="t(`gallery.selection.cups.${size}`)"
|
|
98
|
+
/>
|
|
99
|
+
</GalleryBlock>
|
|
100
|
+
|
|
101
|
+
<GalleryBlock
|
|
102
|
+
:title="t('gallery.selection.sliders')"
|
|
103
|
+
:note="t('gallery.selection.slidersNote')"
|
|
104
|
+
stack
|
|
105
|
+
>
|
|
106
|
+
<M3Slider v-model="volume" :label="t('gallery.selection.volume')" />
|
|
107
|
+
<M3Slider
|
|
108
|
+
v-model="steps"
|
|
109
|
+
:label="t('gallery.selection.steps')"
|
|
110
|
+
:min="0"
|
|
111
|
+
:max="10"
|
|
112
|
+
:step="1"
|
|
113
|
+
ticks
|
|
114
|
+
size="s"
|
|
115
|
+
/>
|
|
116
|
+
<M3Slider v-model="brightness" :label="t('gallery.selection.brightness')" size="m">
|
|
117
|
+
<template #icon><i-ms-light-mode-outline-rounded /></template>
|
|
118
|
+
</M3Slider>
|
|
119
|
+
<M3Slider v-model="brightness" :label="t('gallery.selection.brightness')" size="l" />
|
|
120
|
+
</GalleryBlock>
|
|
121
|
+
|
|
122
|
+
<GalleryBlock
|
|
123
|
+
:title="t('gallery.selection.range')"
|
|
124
|
+
:note="t('gallery.selection.rangeNote')"
|
|
125
|
+
stack
|
|
126
|
+
>
|
|
127
|
+
<M3RangeSlider
|
|
128
|
+
v-model:start="priceFrom"
|
|
129
|
+
v-model:end="priceTo"
|
|
130
|
+
:min="0"
|
|
131
|
+
:max="20000"
|
|
132
|
+
:step="500"
|
|
133
|
+
:min-distance="1000"
|
|
134
|
+
:start-label="t('gallery.selection.priceFrom')"
|
|
135
|
+
:end-label="t('gallery.selection.priceTo')"
|
|
136
|
+
:format="(v) => money.format(v)"
|
|
137
|
+
/>
|
|
138
|
+
<p class="type-body-medium m-0 text-on-surface-variant">
|
|
139
|
+
{{ money.format(priceFrom) }} – {{ money.format(priceTo) }}
|
|
140
|
+
</p>
|
|
141
|
+
<M3RangeSlider
|
|
142
|
+
v-model:start="hourFrom"
|
|
143
|
+
v-model:end="hourTo"
|
|
144
|
+
:min="6"
|
|
145
|
+
:max="22"
|
|
146
|
+
:step="1"
|
|
147
|
+
ticks
|
|
148
|
+
size="s"
|
|
149
|
+
:start-label="t('gallery.selection.opensAt')"
|
|
150
|
+
:end-label="t('gallery.selection.closesAt')"
|
|
151
|
+
:format="(v) => `${v}:00`"
|
|
152
|
+
/>
|
|
153
|
+
</GalleryBlock>
|
|
154
|
+
|
|
155
|
+
<GalleryBlock :title="t('gallery.selection.chips')" :note="t('gallery.selection.chipsNote')">
|
|
156
|
+
<M3Chip
|
|
157
|
+
v-for="filter in FILTERS"
|
|
158
|
+
:key="filter"
|
|
159
|
+
kind="filter"
|
|
160
|
+
:label="t(`gallery.selection.filters.${filter}`)"
|
|
161
|
+
:selected="filters.has(filter)"
|
|
162
|
+
@update:selected="toggleFilter(filter)"
|
|
163
|
+
/>
|
|
164
|
+
<M3Chip kind="assist" :label="t('gallery.selection.addEvent')" elevated>
|
|
165
|
+
<template #icon><i-ms-add-rounded /></template>
|
|
166
|
+
</M3Chip>
|
|
167
|
+
<M3Chip
|
|
168
|
+
v-for="tag in tags"
|
|
169
|
+
:key="tag"
|
|
170
|
+
kind="input"
|
|
171
|
+
removable
|
|
172
|
+
:label="tag"
|
|
173
|
+
:remove-label="t('gallery.selection.remove')"
|
|
174
|
+
@remove="tags = tags.filter((entry) => entry !== tag)"
|
|
175
|
+
/>
|
|
176
|
+
</GalleryBlock>
|
|
177
|
+
</template>
|
|
178
|
+
|
|
179
|
+
<script setup lang="ts">
|
|
180
|
+
import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
|
|
181
|
+
import { WILAYA_OPTIONS } from "@/modules/gallery/composables/wilayas";
|
|
182
|
+
|
|
183
|
+
const { t } = useI18n();
|
|
184
|
+
const SIZES = ["small", "medium", "large"] as const;
|
|
185
|
+
const FILTERS = ["open", "nearby", "rated"] as const;
|
|
186
|
+
|
|
187
|
+
const wifi = ref(true);
|
|
188
|
+
const bluetooth = ref(false);
|
|
189
|
+
const airplane = ref(false);
|
|
190
|
+
const terms = ref(true);
|
|
191
|
+
const invalid = ref(false);
|
|
192
|
+
const cup = ref<(typeof SIZES)[number]>("medium");
|
|
193
|
+
const volume = ref(40);
|
|
194
|
+
const steps = ref(4);
|
|
195
|
+
const guests = ref(2);
|
|
196
|
+
const DAYS = ["sat", "sun", "mon", "tue", "wed", "thu", "fri"] as const;
|
|
197
|
+
const deliveryDays = ref<string[]>(["sun", "tue", "thu"]);
|
|
198
|
+
const zone = ref<number | null>(16);
|
|
199
|
+
const dayOptions = computed(() =>
|
|
200
|
+
DAYS.map((day) => ({ value: day, label: t(`gallery.selection.days.${day}`) })),
|
|
201
|
+
);
|
|
202
|
+
const weight = ref(2.5);
|
|
203
|
+
const units = ref(120);
|
|
204
|
+
const brightness = ref(70);
|
|
205
|
+
const priceFrom = ref(2000);
|
|
206
|
+
const priceTo = ref(12000);
|
|
207
|
+
const hourFrom = ref(8);
|
|
208
|
+
const hourTo = ref(18);
|
|
209
|
+
const money = new Intl.NumberFormat(undefined, { maximumFractionDigits: 0 });
|
|
210
|
+
const filters = ref(new Set<(typeof FILTERS)[number]>(["open"]));
|
|
211
|
+
const tags = ref(["Alger", "Oran", "Constantine"]);
|
|
212
|
+
|
|
213
|
+
function toggleFilter(filter: (typeof FILTERS)[number]) {
|
|
214
|
+
const next = new Set(filters.value);
|
|
215
|
+
if (next.has(filter)) next.delete(filter);
|
|
216
|
+
else next.add(filter);
|
|
217
|
+
filters.value = next;
|
|
218
|
+
}
|
|
219
|
+
</script>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<GalleryBlock :title="t('gallery.shapes.morph')" :note="t('gallery.shapes.morphNote')">
|
|
3
|
+
<div class="grid w-full place-items-center py-2">
|
|
4
|
+
<M3ShapeMorph :shape="selected" :rotate="turns * 30" class="size-40 text-primary">
|
|
5
|
+
<span class="type-label-large text-on-primary">{{ selected }}</span>
|
|
6
|
+
</M3ShapeMorph>
|
|
7
|
+
</div>
|
|
8
|
+
</GalleryBlock>
|
|
9
|
+
|
|
10
|
+
<GalleryBlock :title="t('gallery.shapes.library')" :note="t('gallery.shapes.libraryNote')">
|
|
11
|
+
<div class="grid w-full grid-cols-[repeat(auto-fill,minmax(4.5rem,1fr))] gap-3">
|
|
12
|
+
<button
|
|
13
|
+
v-for="shape in MATERIAL_SHAPES"
|
|
14
|
+
:key="shape"
|
|
15
|
+
type="button"
|
|
16
|
+
class="m3-focus-ring flex flex-col items-center gap-1.5 rounded-md p-1"
|
|
17
|
+
:aria-pressed="shape === selected"
|
|
18
|
+
@click="pick(shape)"
|
|
19
|
+
>
|
|
20
|
+
<M3Shape
|
|
21
|
+
:shape="shape"
|
|
22
|
+
class="size-14 transition-colors duration-200"
|
|
23
|
+
:class="shape === selected ? 'bg-primary' : 'bg-secondary-container'"
|
|
24
|
+
/>
|
|
25
|
+
<span class="type-label-small w-full truncate text-center text-on-surface-variant">{{
|
|
26
|
+
shape
|
|
27
|
+
}}</span>
|
|
28
|
+
</button>
|
|
29
|
+
</div>
|
|
30
|
+
</GalleryBlock>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import { MATERIAL_SHAPES, type MaterialShapeName } from "@cavulsqa/m3e";
|
|
35
|
+
import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
|
|
36
|
+
|
|
37
|
+
const { t } = useI18n();
|
|
38
|
+
const selected = ref<MaterialShapeName>("cookie9Sided");
|
|
39
|
+
const turns = ref(0);
|
|
40
|
+
const haptics = useHaptics();
|
|
41
|
+
|
|
42
|
+
function pick(shape: MaterialShapeName) {
|
|
43
|
+
if (shape === selected.value) return;
|
|
44
|
+
selected.value = shape;
|
|
45
|
+
turns.value += 1;
|
|
46
|
+
haptics.tick();
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<GalleryBlock :title="t('gallery.surfaces.cards')" :note="t('gallery.surfaces.cardsNote')" stack>
|
|
3
|
+
<div class="grid grid-cols-[repeat(auto-fill,minmax(10rem,1fr))] gap-3">
|
|
4
|
+
<M3Card
|
|
5
|
+
v-for="variant in CARDS"
|
|
6
|
+
:key="variant"
|
|
7
|
+
:variant="variant"
|
|
8
|
+
clickable
|
|
9
|
+
@click="tapped(variant)"
|
|
10
|
+
>
|
|
11
|
+
<div class="flex flex-col gap-3 p-4">
|
|
12
|
+
<M3Shape
|
|
13
|
+
shape="cookie4Sided"
|
|
14
|
+
class="size-10 bg-tertiary-container text-on-tertiary-container"
|
|
15
|
+
>
|
|
16
|
+
<i-ms-star-outline-rounded class="size-5" />
|
|
17
|
+
</M3Shape>
|
|
18
|
+
<span class="type-title-medium">{{ variant }}</span>
|
|
19
|
+
<span class="type-body-medium text-on-surface-variant">{{
|
|
20
|
+
t("gallery.surfaces.cardText")
|
|
21
|
+
}}</span>
|
|
22
|
+
</div>
|
|
23
|
+
</M3Card>
|
|
24
|
+
</div>
|
|
25
|
+
</GalleryBlock>
|
|
26
|
+
|
|
27
|
+
<SurfacesContainerTransform />
|
|
28
|
+
|
|
29
|
+
<SectionHeader :title="t('gallery.surfaces.segmented')" />
|
|
30
|
+
<M3List variant="segmented" inset>
|
|
31
|
+
<M3ListItem
|
|
32
|
+
v-for="item in ITEMS"
|
|
33
|
+
:key="item"
|
|
34
|
+
clickable
|
|
35
|
+
:headline="t(`gallery.surfaces.items.${item}.title`)"
|
|
36
|
+
:supporting="t(`gallery.surfaces.items.${item}.text`)"
|
|
37
|
+
:selected="selected === item"
|
|
38
|
+
@click="selected = item"
|
|
39
|
+
>
|
|
40
|
+
<template #leading><i-ms-inventory-2-outline-rounded /></template>
|
|
41
|
+
<template #trailing><M3Badge v-if="item === 'inbox'" :count="12" /></template>
|
|
42
|
+
</M3ListItem>
|
|
43
|
+
</M3List>
|
|
44
|
+
|
|
45
|
+
<SectionHeader :title="t('gallery.surfaces.accordion')" />
|
|
46
|
+
<p class="type-body-small m-0 px-8 pb-3 text-on-surface-variant">
|
|
47
|
+
{{ t("gallery.surfaces.accordionNote") }}
|
|
48
|
+
</p>
|
|
49
|
+
<M3List variant="segmented" inset accordion>
|
|
50
|
+
<M3ListItem
|
|
51
|
+
v-for="question in QUESTIONS"
|
|
52
|
+
:key="question"
|
|
53
|
+
:headline="t(`gallery.surfaces.faq.${question}.q`)"
|
|
54
|
+
>
|
|
55
|
+
<template #leading><i-ms-help-outline-rounded class="rtl:-scale-x-100" /></template>
|
|
56
|
+
<template #details>{{ t(`gallery.surfaces.faq.${question}.a`) }}</template>
|
|
57
|
+
</M3ListItem>
|
|
58
|
+
</M3List>
|
|
59
|
+
|
|
60
|
+
<SectionHeader :title="t('gallery.surfaces.sortable')" />
|
|
61
|
+
<p class="type-body-small m-0 px-8 pb-3 text-on-surface-variant">
|
|
62
|
+
{{ t("gallery.surfaces.sortableNote") }}
|
|
63
|
+
</p>
|
|
64
|
+
<M3List
|
|
65
|
+
variant="segmented"
|
|
66
|
+
inset
|
|
67
|
+
sortable
|
|
68
|
+
:reorder-label="t('gallery.surfaces.reorder')"
|
|
69
|
+
:moved-text="movedText"
|
|
70
|
+
@sort="(from, to) => (route = moveItem(route, from, to))"
|
|
71
|
+
>
|
|
72
|
+
<M3ListItem
|
|
73
|
+
v-for="(stop, index) in route"
|
|
74
|
+
:key="stop"
|
|
75
|
+
:headline="t(`gallery.surfaces.stops.${stop}`)"
|
|
76
|
+
:supporting="t('gallery.surfaces.stopOrder', { n: index + 1 })"
|
|
77
|
+
>
|
|
78
|
+
<template #leading><i-ms-local-shipping-outline-rounded /></template>
|
|
79
|
+
</M3ListItem>
|
|
80
|
+
</M3List>
|
|
81
|
+
|
|
82
|
+
<SectionHeader :title="t('gallery.surfaces.standard')" />
|
|
83
|
+
<M3List variant="standard">
|
|
84
|
+
<M3ListItem :headline="t('gallery.surfaces.wifi')" :supporting="t('gallery.surfaces.wifiText')">
|
|
85
|
+
<template #action><M3Switch v-model="wifi" :label="t('gallery.surfaces.wifi')" /></template>
|
|
86
|
+
</M3ListItem>
|
|
87
|
+
<M3Divider inset="start" />
|
|
88
|
+
<M3ListItem :headline="t('gallery.surfaces.storage')" trailing-text="12.4 GB" />
|
|
89
|
+
</M3List>
|
|
90
|
+
|
|
91
|
+
<SectionHeader :title="t('gallery.tree.title')" />
|
|
92
|
+
<p class="type-body-small m-0 px-8 pb-3 text-on-surface-variant">{{ t("gallery.tree.note") }}</p>
|
|
93
|
+
<div class="mx-4">
|
|
94
|
+
<M3Tree
|
|
95
|
+
v-model:selected="category"
|
|
96
|
+
v-model:expanded="categoriesOpen"
|
|
97
|
+
:items="categories"
|
|
98
|
+
:load="loadChildren"
|
|
99
|
+
:label="t('gallery.tree.categories')"
|
|
100
|
+
:loading-label="t('gallery.loading')"
|
|
101
|
+
>
|
|
102
|
+
<template #icon="{ node, expanded }">
|
|
103
|
+
<i-ms-folder-open-outline-rounded v-if="expanded" />
|
|
104
|
+
<i-ms-folder-outline-rounded v-else-if="node.children || node.lazy" />
|
|
105
|
+
<i-ms-inventory-2-outline-rounded v-else />
|
|
106
|
+
</template>
|
|
107
|
+
</M3Tree>
|
|
108
|
+
</div>
|
|
109
|
+
<SectionHeader :title="t('gallery.tree.permissions')" />
|
|
110
|
+
<div class="mx-4">
|
|
111
|
+
<M3Tree
|
|
112
|
+
v-model:checked="granted"
|
|
113
|
+
v-model:expanded="permissionsOpen"
|
|
114
|
+
mode="check"
|
|
115
|
+
:items="permissions"
|
|
116
|
+
:label="t('gallery.tree.permissions')"
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<SectionHeader :title="t('gallery.surfaces.timeline')" />
|
|
121
|
+
<div class="px-6 pb-2">
|
|
122
|
+
<M3Timeline :label="t('gallery.surfaces.tracking')">
|
|
123
|
+
<M3TimelineItem
|
|
124
|
+
v-for="step in STEPS"
|
|
125
|
+
:key="step.id"
|
|
126
|
+
:title="t(`gallery.surfaces.steps.${step.id}.title`)"
|
|
127
|
+
:supporting="t(`gallery.surfaces.steps.${step.id}.text`)"
|
|
128
|
+
:time="step.time"
|
|
129
|
+
:state="step.state"
|
|
130
|
+
:state-label="t(`gallery.surfaces.states.${step.state}`)"
|
|
131
|
+
>
|
|
132
|
+
<template v-if="step.state === 'current'" #icon
|
|
133
|
+
><i-ms-local-shipping-outline-rounded
|
|
134
|
+
/></template>
|
|
135
|
+
</M3TimelineItem>
|
|
136
|
+
</M3Timeline>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<SectionHeader :title="t('gallery.surfaces.infinite')" />
|
|
140
|
+
<p class="type-body-small m-0 px-8 pb-3 text-on-surface-variant">
|
|
141
|
+
{{ t("gallery.surfaces.infiniteNote") }}
|
|
142
|
+
</p>
|
|
143
|
+
<M3List variant="segmented" inset>
|
|
144
|
+
<M3ListItem
|
|
145
|
+
v-for="order in endless"
|
|
146
|
+
:key="order"
|
|
147
|
+
:headline="t('gallery.tabs.order', { n: order })"
|
|
148
|
+
:supporting="t('gallery.surfaces.page', { n: Math.ceil((order - 5000) / 15) })"
|
|
149
|
+
>
|
|
150
|
+
<template #leading><i-ms-receipt-long-outline-rounded /></template>
|
|
151
|
+
</M3ListItem>
|
|
152
|
+
</M3List>
|
|
153
|
+
<M3InfiniteScroll
|
|
154
|
+
:load="loadMore"
|
|
155
|
+
:loading-label="t('gallery.surfaces.loadingMore')"
|
|
156
|
+
:error-text="t('gallery.surfaces.loadFailed')"
|
|
157
|
+
:retry-label="t('gallery.surfaces.retry')"
|
|
158
|
+
:end-text="t('gallery.surfaces.allLoaded')"
|
|
159
|
+
/>
|
|
160
|
+
</template>
|
|
161
|
+
|
|
162
|
+
<script setup lang="ts">
|
|
163
|
+
import { moveItem } from "@cavulsqa/m3e-vue";
|
|
164
|
+
import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
|
|
165
|
+
import SurfacesContainerTransform from "@/modules/gallery/components/surfaces/SurfacesContainerTransform.vue";
|
|
166
|
+
import { useTreeDemo } from "@/modules/gallery/composables/useTreeDemo";
|
|
167
|
+
|
|
168
|
+
const { t } = useI18n();
|
|
169
|
+
const snackbar = useSnackbar();
|
|
170
|
+
const CARDS = ["elevated", "filled", "outlined"] as const;
|
|
171
|
+
const ITEMS = ["inbox", "drafts", "archive"] as const;
|
|
172
|
+
const QUESTIONS = ["offline", "sync", "storage", "export"] as const;
|
|
173
|
+
const { categories, permissions, loadChildren } = useTreeDemo();
|
|
174
|
+
const category = ref<string | null>("orange");
|
|
175
|
+
const categoriesOpen = ref(["drinks", "juice"]);
|
|
176
|
+
const granted = ref(["sales.read", "sales.create", "stock.read"]);
|
|
177
|
+
const permissionsOpen = ref(["sales"]);
|
|
178
|
+
const STEPS = [
|
|
179
|
+
{ id: "placed", time: "08:12", state: "done" },
|
|
180
|
+
{ id: "confirmed", time: "08:40", state: "done" },
|
|
181
|
+
{ id: "picked", time: "10:05", state: "done" },
|
|
182
|
+
{ id: "transit", time: "11:20", state: "current" },
|
|
183
|
+
{ id: "delivered", time: "", state: "upcoming" },
|
|
184
|
+
] as const;
|
|
185
|
+
const PAGE = 15;
|
|
186
|
+
const PAGES = 5;
|
|
187
|
+
const endless = ref<number[]>([]);
|
|
188
|
+
let failedOnce = false;
|
|
189
|
+
|
|
190
|
+
async function loadMore(): Promise<boolean> {
|
|
191
|
+
await new Promise((resolve) => setTimeout(resolve, 900));
|
|
192
|
+
const page = endless.value.length / PAGE;
|
|
193
|
+
if (page === 2 && !failedOnce) {
|
|
194
|
+
failedOnce = true;
|
|
195
|
+
throw new Error("simulated network failure");
|
|
196
|
+
}
|
|
197
|
+
const start = 5001 + endless.value.length;
|
|
198
|
+
endless.value = [...endless.value, ...Array.from({ length: PAGE }, (_, i) => start + i)];
|
|
199
|
+
return page + 1 < PAGES;
|
|
200
|
+
}
|
|
201
|
+
const route = ref(["warehouse", "market", "pharmacy", "school", "bakery"]);
|
|
202
|
+
|
|
203
|
+
function movedText(label: string, position: number, count: number) {
|
|
204
|
+
return t("gallery.surfaces.moved", { label, position, count });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const selected = ref<(typeof ITEMS)[number]>("inbox");
|
|
208
|
+
const wifi = ref(true);
|
|
209
|
+
|
|
210
|
+
function tapped(variant: string) {
|
|
211
|
+
void snackbar.show(t("gallery.surfaces.tapped", { variant }));
|
|
212
|
+
}
|
|
213
|
+
</script>
|