@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.
Files changed (199) hide show
  1. package/README.md +12 -1
  2. package/bin/create.mjs +18 -25
  3. package/lib/templates.mjs +56 -0
  4. package/package.json +13 -5
  5. package/templates/f7-app/auto-imports.d.ts +9 -0
  6. package/templates/f7-app/package.json +6 -3
  7. package/templates/f7-app/src/env.d.ts +1 -0
  8. package/templates/f7-app/src/main.ts +3 -0
  9. package/templates/f7-app/src/plugins/bootstrapError.ts +2 -0
  10. package/templates/f7-app/src/plugins/recorder.plugin.ts +155 -0
  11. package/templates/f7-app/src/shared/recorder/capacitorSink.ts +124 -0
  12. package/templates/f7-app/vite.config.ts +1 -0
  13. package/templates/m3e-app/.claude/rules/data-fetching.md +68 -0
  14. package/templates/m3e-app/.claude/rules/database.md +106 -0
  15. package/templates/m3e-app/.claude/rules/m3e-ui.md +48 -0
  16. package/templates/m3e-app/.claude/rules/modules.md +43 -0
  17. package/templates/m3e-app/.claude/rules/native.md +60 -0
  18. package/templates/m3e-app/.claude/skills/m3-expressive/SKILL.md +68 -0
  19. package/templates/m3e-app/.claude/skills/m3-expressive/color.md +44 -0
  20. package/templates/m3e-app/.claude/skills/m3-expressive/components.md +325 -0
  21. package/templates/m3e-app/.claude/skills/m3-expressive/layout.md +42 -0
  22. package/templates/m3e-app/.claude/skills/m3-expressive/motion.md +51 -0
  23. package/templates/m3e-app/.claude/skills/m3-expressive/shapes-type.md +48 -0
  24. package/templates/m3e-app/.claude/skills/m3-expressive/sources.md +53 -0
  25. package/templates/m3e-app/.claude/skills/module-architecture/SKILL.md +65 -0
  26. package/templates/m3e-app/.claude/skills/module-architecture/file-templates.md +178 -0
  27. package/templates/m3e-app/.claude/skills/reactive-data/SKILL.md +90 -0
  28. package/templates/m3e-app/.claude/skills/reactive-data/testing.md +55 -0
  29. package/templates/m3e-app/.env.example +32 -0
  30. package/templates/m3e-app/CLAUDE.md +93 -0
  31. package/templates/m3e-app/auto-imports.d.ts +851 -0
  32. package/templates/m3e-app/capacitor.config.ts +44 -0
  33. package/templates/m3e-app/components.d.ts +252 -0
  34. package/templates/m3e-app/index.html +16 -0
  35. package/templates/m3e-app/package.json +108 -0
  36. package/templates/m3e-app/src/App.vue +129 -0
  37. package/templates/m3e-app/src/app/pragmas.config.ts +35 -0
  38. package/templates/m3e-app/src/app/scroll.config.ts +20 -0
  39. package/templates/m3e-app/src/app/storage.config.ts +65 -0
  40. package/templates/m3e-app/src/app/tabs.ts +33 -0
  41. package/templates/m3e-app/src/app/theme.config.ts +51 -0
  42. package/templates/m3e-app/src/assets/css/app.css +18 -0
  43. package/templates/m3e-app/src/assets/css/base.css +53 -0
  44. package/templates/m3e-app/src/assets/css/layout/container-transform.css +113 -0
  45. package/templates/m3e-app/src/assets/css/layout/shell.css +69 -0
  46. package/templates/m3e-app/src/assets/css/layout/transitions.css +121 -0
  47. package/templates/m3e-app/src/assets/css/m3e.css +6 -0
  48. package/templates/m3e-app/src/assets/css/theme/framework7.css +18 -0
  49. package/templates/m3e-app/src/assets/css/theme/tailwind.css +365 -0
  50. package/templates/m3e-app/src/domains/benchmark/benchmark.dataset.ts +209 -0
  51. package/templates/m3e-app/src/domains/benchmark/benchmark.suite.ts +662 -0
  52. package/templates/m3e-app/src/domains/sales/sales.repository.ts +458 -0
  53. package/templates/m3e-app/src/env.d.ts +40 -0
  54. package/templates/m3e-app/src/locales/ar.json +1260 -0
  55. package/templates/m3e-app/src/locales/en.json +1260 -0
  56. package/templates/m3e-app/src/locales/fr.json +1260 -0
  57. package/templates/m3e-app/src/main.ts +41 -0
  58. package/templates/m3e-app/src/modules/demo/components/DemoBenchmark.vue +119 -0
  59. package/templates/m3e-app/src/modules/demo/components/DemoBusLog.vue +63 -0
  60. package/templates/m3e-app/src/modules/demo/components/DemoCreateOrderSheet.vue +203 -0
  61. package/templates/m3e-app/src/modules/demo/components/DemoMetricsSheet.vue +75 -0
  62. package/templates/m3e-app/src/modules/demo/components/DemoOrderList.vue +75 -0
  63. package/templates/m3e-app/src/modules/demo/components/DemoPipelineBenchmark.vue +65 -0
  64. package/templates/m3e-app/src/modules/demo/components/DemoStatCards.vue +71 -0
  65. package/templates/m3e-app/src/modules/demo/composables/useBenchmark.ts +139 -0
  66. package/templates/m3e-app/src/modules/demo/composables/useOrderStatus.ts +64 -0
  67. package/templates/m3e-app/src/modules/demo/composables/useReactiveDemo.ts +171 -0
  68. package/templates/m3e-app/src/modules/demo/router/routes/demo.routes.ts +22 -0
  69. package/templates/m3e-app/src/modules/demo/views/DemoView.vue +210 -0
  70. package/templates/m3e-app/src/modules/demo/views/OrderDetailView.vue +136 -0
  71. package/templates/m3e-app/src/modules/demo/views/OrderSearchView.vue +74 -0
  72. package/templates/m3e-app/src/modules/gallery/components/GalleryBlock.vue +16 -0
  73. package/templates/m3e-app/src/modules/gallery/components/GalleryCarouselTile.vue +71 -0
  74. package/templates/m3e-app/src/modules/gallery/components/GalleryCustomerForm.vue +76 -0
  75. package/templates/m3e-app/src/modules/gallery/components/GalleryProofOfDelivery.vue +69 -0
  76. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaDay.vue +106 -0
  77. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaMonth.vue +40 -0
  78. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaVisitList.vue +45 -0
  79. package/templates/m3e-app/src/modules/gallery/components/chat/ChatAttachSheet.vue +106 -0
  80. package/templates/m3e-app/src/modules/gallery/components/chat/ChatContactPicker.vue +85 -0
  81. package/templates/m3e-app/src/modules/gallery/components/chat/ChatInviteComposer.vue +131 -0
  82. package/templates/m3e-app/src/modules/gallery/components/chat/ChatPollComposer.vue +148 -0
  83. package/templates/m3e-app/src/modules/gallery/components/chat/ChatRecentPhotos.vue +62 -0
  84. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsAccount.vue +79 -0
  85. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsTags.vue +53 -0
  86. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsVerification.vue +73 -0
  87. package/templates/m3e-app/src/modules/gallery/components/inputs/PasswordStrength.vue +37 -0
  88. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryButtons.vue +128 -0
  89. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCarousels.vue +236 -0
  90. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCharts.vue +84 -0
  91. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryFabs.vue +70 -0
  92. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryInputs.vue +219 -0
  93. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryNavigation.vue +141 -0
  94. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryOverlays.vue +368 -0
  95. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryPickers.vue +175 -0
  96. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryProgress.vue +118 -0
  97. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryScale.vue +103 -0
  98. package/templates/m3e-app/src/modules/gallery/components/sections/GallerySelection.vue +219 -0
  99. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryShapes.vue +48 -0
  100. package/templates/m3e-app/src/modules/gallery/components/sections/GallerySurfaces.vue +213 -0
  101. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryTables.vue +185 -0
  102. package/templates/m3e-app/src/modules/gallery/components/surfaces/SurfacesContainerTransform.vue +46 -0
  103. package/templates/m3e-app/src/modules/gallery/composables/chatTeam.ts +18 -0
  104. package/templates/m3e-app/src/modules/gallery/composables/composeKind.ts +2 -0
  105. package/templates/m3e-app/src/modules/gallery/composables/currentPosition.ts +35 -0
  106. package/templates/m3e-app/src/modules/gallery/composables/demoOrders.ts +29 -0
  107. package/templates/m3e-app/src/modules/gallery/composables/featuredStories.ts +73 -0
  108. package/templates/m3e-app/src/modules/gallery/composables/fieldFormats.ts +36 -0
  109. package/templates/m3e-app/src/modules/gallery/composables/openExternal.ts +11 -0
  110. package/templates/m3e-app/src/modules/gallery/composables/routePlan.ts +90 -0
  111. package/templates/m3e-app/src/modules/gallery/composables/useAgenda.ts +61 -0
  112. package/templates/m3e-app/src/modules/gallery/composables/useChatCustomers.ts +31 -0
  113. package/templates/m3e-app/src/modules/gallery/composables/useChatDemo.ts +299 -0
  114. package/templates/m3e-app/src/modules/gallery/composables/useGallerySections.ts +230 -0
  115. package/templates/m3e-app/src/modules/gallery/composables/useLocalAttachments.ts +71 -0
  116. package/templates/m3e-app/src/modules/gallery/composables/useLocationShare.ts +38 -0
  117. package/templates/m3e-app/src/modules/gallery/composables/usePhotoScenes.ts +82 -0
  118. package/templates/m3e-app/src/modules/gallery/composables/useTreeDemo.ts +67 -0
  119. package/templates/m3e-app/src/modules/gallery/composables/wilayas.ts +67 -0
  120. package/templates/m3e-app/src/modules/gallery/router/routes/gallery.routes.ts +52 -0
  121. package/templates/m3e-app/src/modules/gallery/views/GalleryAgendaView.vue +117 -0
  122. package/templates/m3e-app/src/modules/gallery/views/GalleryChatView.vue +292 -0
  123. package/templates/m3e-app/src/modules/gallery/views/GalleryContactsView.vue +77 -0
  124. package/templates/m3e-app/src/modules/gallery/views/GalleryFeaturedView.vue +60 -0
  125. package/templates/m3e-app/src/modules/gallery/views/GalleryLoginView.vue +135 -0
  126. package/templates/m3e-app/src/modules/gallery/views/GalleryOnboardingView.vue +116 -0
  127. package/templates/m3e-app/src/modules/gallery/views/GallerySectionView.vue +27 -0
  128. package/templates/m3e-app/src/modules/gallery/views/GalleryTabsView.vue +135 -0
  129. package/templates/m3e-app/src/modules/gallery/views/GalleryView.vue +50 -0
  130. package/templates/m3e-app/src/modules/home/components/HomeHero.vue +57 -0
  131. package/templates/m3e-app/src/modules/home/composables/useHomeFeatures.ts +128 -0
  132. package/templates/m3e-app/src/modules/home/composables/useOpenFeature.ts +22 -0
  133. package/templates/m3e-app/src/modules/home/router/routes/home.routes.ts +21 -0
  134. package/templates/m3e-app/src/modules/home/views/FeatureDetailView.vue +66 -0
  135. package/templates/m3e-app/src/modules/home/views/HomeView.vue +47 -0
  136. package/templates/m3e-app/src/modules/settings/components/RolePalette.vue +38 -0
  137. package/templates/m3e-app/src/modules/settings/components/SeedSwatches.vue +41 -0
  138. package/templates/m3e-app/src/modules/settings/components/SettingsChoice.vue +43 -0
  139. package/templates/m3e-app/src/modules/settings/components/StudioPreview.vue +52 -0
  140. package/templates/m3e-app/src/modules/settings/router/routes/settings.routes.ts +17 -0
  141. package/templates/m3e-app/src/modules/settings/types.ts +7 -0
  142. package/templates/m3e-app/src/modules/settings/views/ColorStudioView.vue +166 -0
  143. package/templates/m3e-app/src/modules/settings/views/SettingsView.vue +157 -0
  144. package/templates/m3e-app/src/plugins/bootstrapError.ts +62 -0
  145. package/templates/m3e-app/src/plugins/capacitor/index.ts +14 -0
  146. package/templates/m3e-app/src/plugins/capacitor/useAndroidBackButton.ts +36 -0
  147. package/templates/m3e-app/src/plugins/capacitor/useKeyboard.ts +48 -0
  148. package/templates/m3e-app/src/plugins/capacitor/useSplashScreen.ts +43 -0
  149. package/templates/m3e-app/src/plugins/capacitor/useStatusBar.ts +16 -0
  150. package/templates/m3e-app/src/plugins/framework7.plugin.ts +36 -0
  151. package/templates/m3e-app/src/plugins/i18n.plugin.ts +87 -0
  152. package/templates/m3e-app/src/plugins/m3e.plugin.ts +22 -0
  153. package/templates/m3e-app/src/plugins/seed.plugin.ts +7 -0
  154. package/templates/m3e-app/src/plugins/sqlite.plugin.ts +32 -0
  155. package/templates/m3e-app/src/router/global/global.routes.ts +12 -0
  156. package/templates/m3e-app/src/router/index.ts +20 -0
  157. package/templates/m3e-app/src/shared/components/error/404.vue +13 -0
  158. package/templates/m3e-app/src/shared/components/layout/EmptyState.vue +30 -0
  159. package/templates/m3e-app/src/shared/components/layout/SectionHeader.vue +10 -0
  160. package/templates/m3e-app/src/shared/components/page/AppPage.vue +104 -0
  161. package/templates/m3e-app/src/shared/composables/navigation/useActiveTab.ts +39 -0
  162. package/templates/m3e-app/src/shared/composables/navigation/useContainerTransform.ts +117 -0
  163. package/templates/m3e-app/src/shared/composables/navigation/useNavigationGuard.ts +48 -0
  164. package/templates/m3e-app/src/shared/composables/navigation/useNavigationVisibility.ts +64 -0
  165. package/templates/m3e-app/src/shared/composables/navigation/useViewRouter.ts +25 -0
  166. package/templates/m3e-app/src/shared/composables/navigation/useWindowClass.ts +22 -0
  167. package/templates/m3e-app/src/shared/composables/theme/useThemeSettings.ts +155 -0
  168. package/templates/m3e-app/src/shared/database/candidates/capacitorSqlite.ts +36 -0
  169. package/templates/m3e-app/src/shared/database/candidates/index.ts +4 -0
  170. package/templates/m3e-app/src/shared/database/candidates/opfsSahPool.ts +25 -0
  171. package/templates/m3e-app/src/shared/database/candidates/types.ts +56 -0
  172. package/templates/m3e-app/src/shared/database/candidates/waSqlite.ts +56 -0
  173. package/templates/m3e-app/src/shared/database/database.ts +219 -0
  174. package/templates/m3e-app/src/shared/database/index.ts +3 -0
  175. package/templates/m3e-app/src/shared/database/migrations.ts +223 -0
  176. package/templates/m3e-app/src/shared/database/opfs.worker.ts +5 -0
  177. package/templates/m3e-app/src/shared/database/queries.ts +26 -0
  178. package/templates/m3e-app/src/shared/database/schema.ts +153 -0
  179. package/templates/m3e-app/src/shared/database/storage.ts +64 -0
  180. package/templates/m3e-app/src/shared/database/wa.worker.ts +5 -0
  181. package/templates/m3e-app/src/shared/utils/lazyRoute.ts +41 -0
  182. package/templates/m3e-app/src/shared/utils/resolvers/resolvers.ts +42 -0
  183. package/templates/m3e-app/src/shared/utils/textDirection.ts +22 -0
  184. package/templates/m3e-app/src/shared/utils/theme/themeSettings.ts +59 -0
  185. package/templates/m3e-app/src/shared/utils/tone.ts +8 -0
  186. package/templates/m3e-app/tests/benchmark.suite.test.ts +104 -0
  187. package/templates/m3e-app/tests/containerTransform.test.ts +58 -0
  188. package/templates/m3e-app/tests/fieldFormats.test.ts +25 -0
  189. package/templates/m3e-app/tests/lazyRoute.test.ts +30 -0
  190. package/templates/m3e-app/tests/locales.test.ts +73 -0
  191. package/templates/m3e-app/tests/migrations.test.ts +74 -0
  192. package/templates/m3e-app/tests/navigationGuard.test.ts +82 -0
  193. package/templates/m3e-app/tests/openDatabase.test.ts +54 -0
  194. package/templates/m3e-app/tests/sales.repository.test.ts +329 -0
  195. package/templates/m3e-app/tests/storage.test.ts +117 -0
  196. package/templates/m3e-app/tests/textDirection.test.ts +11 -0
  197. package/templates/m3e-app/tooling/linkedPackages.ts +112 -0
  198. package/templates/m3e-app/tsconfig.json +21 -0
  199. package/templates/m3e-app/vite.config.ts +144 -0
@@ -0,0 +1,368 @@
1
+ <template>
2
+ <GalleryBlock :title="t('gallery.overlays.sheet')" :note="t('gallery.overlays.sheetNote')">
3
+ <M3Button variant="tonal" @click="sheetOpen = true">{{
4
+ t("gallery.overlays.openSheet")
5
+ }}</M3Button>
6
+ <M3Button variant="outlined" @click="openActions">{{
7
+ t("gallery.overlays.openActions")
8
+ }}</M3Button>
9
+ </GalleryBlock>
10
+
11
+ <GalleryBlock :title="t('gallery.overlays.standard')" :note="t('gallery.overlays.standardNote')">
12
+ <M3Button variant="tonal" @click="toggleStandard">{{
13
+ standardDetent === "hidden"
14
+ ? t("gallery.overlays.showStandard")
15
+ : t("gallery.overlays.hideStandard")
16
+ }}</M3Button>
17
+ </GalleryBlock>
18
+
19
+ <GalleryBlock :title="t('gallery.overlays.side')" :note="t('gallery.overlays.sideNote')">
20
+ <M3Button variant="tonal" @click="sideOpen = true">{{
21
+ t("gallery.overlays.openSide")
22
+ }}</M3Button>
23
+ <M3Button variant="outlined" @click="railOpen = true">
24
+ <template #icon><i-ms-menu-rounded /></template>
25
+ {{ t("gallery.overlays.openRail") }}
26
+ </M3Button>
27
+ </GalleryBlock>
28
+
29
+ <GalleryBlock :title="t('gallery.overlays.tooltips')" :note="t('gallery.overlays.tooltipsNote')">
30
+ <M3Tooltip :text="t('gallery.buttons.share')">
31
+ <M3IconButton :label="t('gallery.buttons.share')" variant="tonal"
32
+ ><i-ms-share-outline-rounded
33
+ /></M3IconButton>
34
+ </M3Tooltip>
35
+ <M3Tooltip rich :title="t('gallery.overlays.richTitle')" :text="t('gallery.overlays.richText')">
36
+ <M3Button variant="text">
37
+ <template #icon><i-ms-info-outline-rounded /></template>
38
+ {{ t("gallery.overlays.whatsThis") }}
39
+ </M3Button>
40
+ <template #actions="{ close }">
41
+ <M3Button variant="text" size="xs" @click="close">{{
42
+ t("gallery.overlays.gotIt")
43
+ }}</M3Button>
44
+ </template>
45
+ </M3Tooltip>
46
+ </GalleryBlock>
47
+
48
+ <GalleryBlock
49
+ :title="t('gallery.overlays.fullscreen')"
50
+ :note="t('gallery.overlays.fullscreenNote')"
51
+ >
52
+ <M3Button variant="tonal" @click="formOpen = true">{{
53
+ t("gallery.overlays.newCustomer")
54
+ }}</M3Button>
55
+ </GalleryBlock>
56
+
57
+ <GalleryCustomerForm
58
+ v-model:open="formOpen"
59
+ @saved="(name) => snackbar.show(t('gallery.overlays.customerSaved', { name }))"
60
+ />
61
+
62
+ <GalleryBlock :title="t('gallery.overlays.dialog')" :note="t('gallery.overlays.dialogNote')">
63
+ <M3Button variant="tonal" @click="confirm">{{ t("gallery.overlays.openDialog") }}</M3Button>
64
+ </GalleryBlock>
65
+
66
+ <GalleryBlock :title="t('gallery.overlays.menu')" :note="t('gallery.overlays.menuNote')">
67
+ <div ref="menuAnchor" class="inline-flex">
68
+ <M3Button variant="outlined" @click="menuOpen = !menuOpen">
69
+ {{ t("gallery.overlays.sortBy", { order: t(`gallery.overlays.orders.${sort}`) }) }}
70
+ <template #trailing><i-ms-sort-rounded /></template>
71
+ </M3Button>
72
+ </div>
73
+ <M3Menu v-model:open="menuOpen" :anchor="menuAnchor" :label="t('gallery.overlays.menu')">
74
+ <M3MenuGroup :label="t('gallery.overlays.sort')">
75
+ <M3MenuItem
76
+ v-for="order in ORDERS"
77
+ :key="order"
78
+ checkable
79
+ :selected="sort === order"
80
+ :label="t(`gallery.overlays.orders.${order}`)"
81
+ @select="sort = order"
82
+ />
83
+ </M3MenuGroup>
84
+ <M3MenuGroup>
85
+ <M3MenuItem
86
+ :label="t('gallery.overlays.groupBy')"
87
+ :supporting="t(`gallery.overlays.groups.${groupBy}`)"
88
+ >
89
+ <template #icon><i-ms-category-outline-rounded /></template>
90
+ <template #submenu>
91
+ <M3MenuItem
92
+ v-for="group in GROUPS"
93
+ :key="group"
94
+ checkable
95
+ :selected="groupBy === group"
96
+ :label="t(`gallery.overlays.groups.${group}`)"
97
+ @select="groupBy = group"
98
+ />
99
+ </template>
100
+ </M3MenuItem>
101
+ <M3MenuItem
102
+ :label="t('gallery.overlays.reset')"
103
+ tone="destructive"
104
+ @select="sort = 'recent'"
105
+ >
106
+ <template #icon><i-ms-restart-alt-rounded /></template>
107
+ </M3MenuItem>
108
+ </M3MenuGroup>
109
+ </M3Menu>
110
+ </GalleryBlock>
111
+
112
+ <GalleryBlock :title="t('gallery.overlays.popover')" :note="t('gallery.overlays.popoverNote')">
113
+ <div ref="popoverAnchor" class="inline-flex">
114
+ <M3Button variant="tonal" :aria-expanded="popoverOpen" @click="popoverOpen = !popoverOpen">
115
+ {{ t("gallery.overlays.cases", { n: cases }) }}
116
+ <template #trailing><i-ms-expand-more-rounded /></template>
117
+ </M3Button>
118
+ </div>
119
+ <M3Popover
120
+ v-model:open="popoverOpen"
121
+ :anchor="popoverAnchor"
122
+ :label="t('gallery.overlays.quantity')"
123
+ >
124
+ <template #default="{ close }">
125
+ <div class="flex flex-col gap-3 p-4">
126
+ <span class="type-title-small text-on-surface">{{ t("gallery.overlays.quantity") }}</span>
127
+ <M3Stepper
128
+ v-model="cases"
129
+ :label="t('gallery.overlays.quantity')"
130
+ :min="1"
131
+ :max="48"
132
+ :decrement-label="t('gallery.selection.decrease')"
133
+ :increment-label="t('gallery.selection.increase')"
134
+ />
135
+ <span class="type-body-small text-on-surface-variant">{{
136
+ t("gallery.overlays.quantityNote")
137
+ }}</span>
138
+ <M3Button variant="text" class="self-end" @click="close">{{
139
+ t("gallery.overlays.done")
140
+ }}</M3Button>
141
+ </div>
142
+ </template>
143
+ </M3Popover>
144
+ </GalleryBlock>
145
+
146
+ <GalleryBlock
147
+ :title="t('gallery.overlays.notification')"
148
+ :note="t('gallery.overlays.notificationNote')"
149
+ >
150
+ <M3Button variant="tonal" @click="notifyOrder">{{
151
+ t("gallery.overlays.notifyOrder")
152
+ }}</M3Button>
153
+ <M3Button variant="outlined" @click="notifySync">{{
154
+ t("gallery.overlays.notifySync")
155
+ }}</M3Button>
156
+ <M3Button variant="text" @click="notifyBurst">{{ t("gallery.overlays.notifyBurst") }}</M3Button>
157
+ </GalleryBlock>
158
+
159
+ <GalleryBlock :title="t('gallery.overlays.snackbar')" :note="t('gallery.overlays.snackbarNote')">
160
+ <M3Button variant="tonal" @click="archive">{{ t("gallery.overlays.archive") }}</M3Button>
161
+ </GalleryBlock>
162
+
163
+ <M3SideSheet
164
+ v-model:open="sideOpen"
165
+ :title="t('gallery.overlays.filters')"
166
+ :close-label="t('shell.dismiss')"
167
+ >
168
+ <div class="flex flex-col gap-4 px-6 pb-6">
169
+ <span class="type-title-small text-on-surface-variant">{{ t("gallery.overlays.sort") }}</span>
170
+ <div class="flex flex-wrap gap-2">
171
+ <M3Chip
172
+ v-for="order in ORDERS"
173
+ :key="order"
174
+ kind="filter"
175
+ :label="t(`gallery.overlays.orders.${order}`)"
176
+ :selected="sort === order"
177
+ @update:selected="sort = order"
178
+ />
179
+ </div>
180
+ </div>
181
+ <template #footer>
182
+ <M3Button class="w-full" @click="sideOpen = false">{{ t("gallery.overlays.done") }}</M3Button>
183
+ </template>
184
+ </M3SideSheet>
185
+
186
+ <M3ModalNavigationRail
187
+ v-model:open="railOpen"
188
+ v-model:selected="destination"
189
+ :label="t('gallery.overlays.openRail')"
190
+ >
191
+ <M3NavigationItem
192
+ v-for="item in DESTINATIONS"
193
+ :key="item"
194
+ :value="item"
195
+ :label="t(`gallery.navigation.${item}`)"
196
+ >
197
+ <template #icon="{ selected }">
198
+ <i-ms-star-rounded v-if="selected" />
199
+ <i-ms-star-outline-rounded v-else />
200
+ </template>
201
+ </M3NavigationItem>
202
+ </M3ModalNavigationRail>
203
+
204
+ <M3StandardBottomSheet
205
+ v-model:detent="standardDetent"
206
+ :label="t('gallery.overlays.nearby')"
207
+ :title="t('gallery.overlays.nearby')"
208
+ :peek-height="112"
209
+ :expand-label="t('gallery.overlays.expandSheet')"
210
+ :collapse-label="t('gallery.overlays.collapseSheet')"
211
+ hideable
212
+ >
213
+ <M3List variant="segmented" inset>
214
+ <M3ListItem
215
+ v-for="stop in 24"
216
+ :key="stop"
217
+ clickable
218
+ :headline="t('gallery.overlays.stop', { n: stop })"
219
+ :supporting="t('gallery.overlays.stopNote', { minutes: stop * 3 })"
220
+ >
221
+ <template #leading><i-ms-location-on-outline-rounded /></template>
222
+ </M3ListItem>
223
+ </M3List>
224
+ </M3StandardBottomSheet>
225
+
226
+ <M3BottomSheet v-model:open="sheetOpen" :title="t('gallery.overlays.sheetTitle')">
227
+ <p class="type-body-medium m-0 px-6 pb-4 text-on-surface-variant">
228
+ {{ t("gallery.overlays.sheetText") }}
229
+ </p>
230
+ <M3List variant="segmented" inset>
231
+ <M3ListItem
232
+ v-for="line in 12"
233
+ :key="line"
234
+ :headline="t('gallery.overlays.row', { n: line })"
235
+ />
236
+ </M3List>
237
+ <template #footer>
238
+ <M3Button class="w-full" size="m" @click="sheetOpen = false">{{
239
+ t("gallery.overlays.done")
240
+ }}</M3Button>
241
+ </template>
242
+ </M3BottomSheet>
243
+ </template>
244
+
245
+ <script setup lang="ts">
246
+ import type { SheetDetent } from "@cavulsqa/m3e-vue";
247
+ import { markRaw } from "vue";
248
+ import CloudDoneIcon from "~icons/material-symbols/cloud-done-outline-rounded";
249
+ import ContentCopyIcon from "~icons/material-symbols/content-copy-outline-rounded";
250
+ import ShoppingIcon from "~icons/material-symbols/shopping-bag-outline-rounded";
251
+ import DeleteIcon from "~icons/material-symbols/delete-outline-rounded";
252
+ import EditIcon from "~icons/material-symbols/edit-outline-rounded";
253
+ import ShareIcon from "~icons/material-symbols/share-outline-rounded";
254
+ import StarIcon from "~icons/material-symbols/star-outline-rounded";
255
+ import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
256
+ import GalleryCustomerForm from "@/modules/gallery/components/GalleryCustomerForm.vue";
257
+
258
+ const { t } = useI18n();
259
+ const snackbar = useSnackbar();
260
+ const dialog = useDialog();
261
+ const actionSheet = useActionSheet();
262
+ const notification = useNotification();
263
+
264
+ const ORDERS = ["recent", "name", "amount"] as const;
265
+ const DESTINATIONS = ["inbox", "starred", "saved"] as const;
266
+ const GROUPS = ["none", "customer", "status"] as const;
267
+ const sideOpen = ref(false);
268
+ const railOpen = ref(false);
269
+ const destination = ref<string>("inbox");
270
+ const sheetOpen = ref(false);
271
+ const formOpen = ref(false);
272
+ const standardDetent = ref<SheetDetent>("hidden");
273
+ const menuOpen = ref(false);
274
+ const sort = ref<(typeof ORDERS)[number]>("recent");
275
+ const groupBy = ref<(typeof GROUPS)[number]>("none");
276
+ const menuAnchor = useTemplateRef<HTMLElement>("menuAnchor");
277
+ const popoverOpen = ref(false);
278
+ const cases = ref(6);
279
+ const popoverAnchor = useTemplateRef<HTMLElement>("popoverAnchor");
280
+
281
+ function toggleStandard() {
282
+ standardDetent.value = standardDetent.value === "hidden" ? "peek" : "hidden";
283
+ }
284
+
285
+ async function notifyOrder() {
286
+ const result = await notification.show({
287
+ source: t("gallery.overlays.ordersSource"),
288
+ meta: t("gallery.overlays.now"),
289
+ title: t("gallery.overlays.orderTitle"),
290
+ text: t("gallery.overlays.orderText"),
291
+ icon: markRaw(ShoppingIcon),
292
+ });
293
+ if (result === "opened") void snackbar.show(t("gallery.overlays.orderOpened"));
294
+ }
295
+
296
+ function notifySync() {
297
+ void notification.show({
298
+ source: t("gallery.overlays.syncSource"),
299
+ meta: t("gallery.overlays.now"),
300
+ title: t("gallery.overlays.syncTitle"),
301
+ icon: markRaw(CloudDoneIcon),
302
+ duration: 3000,
303
+ });
304
+ }
305
+
306
+ function notifyBurst() {
307
+ const visits = ["Supérette El Feth", "Alimentation Bachir", "Market Ennour"];
308
+ visits.forEach((shop, index) => {
309
+ setTimeout(() => {
310
+ void notification.show({
311
+ source: t("gallery.overlays.ordersSource"),
312
+ meta: t("gallery.overlays.now"),
313
+ title: t("gallery.overlays.burstTitle", { shop }),
314
+ text: t("gallery.overlays.burstText"),
315
+ icon: markRaw(ShoppingIcon),
316
+ duration: 8000,
317
+ });
318
+ }, index * 600);
319
+ });
320
+ }
321
+
322
+ async function openActions() {
323
+ const choice = await actionSheet.open({
324
+ title: t("gallery.overlays.actionsTitle"),
325
+ supporting: t("gallery.overlays.actionsText"),
326
+ quickActions: [
327
+ { id: "share", label: t("gallery.buttons.share"), icon: markRaw(ShareIcon) },
328
+ { id: "copy", label: t("gallery.overlays.copy"), icon: markRaw(ContentCopyIcon) },
329
+ { id: "star", label: t("gallery.buttons.star"), icon: markRaw(StarIcon) },
330
+ ],
331
+ groups: [
332
+ { items: [{ id: "edit", label: t("gallery.buttons.edit"), icon: markRaw(EditIcon) }] },
333
+ {
334
+ items: [
335
+ {
336
+ id: "delete",
337
+ label: t("gallery.overlays.delete"),
338
+ supporting: t("gallery.overlays.deleteNote"),
339
+ icon: markRaw(DeleteIcon),
340
+ tone: "destructive",
341
+ },
342
+ ],
343
+ },
344
+ ],
345
+ });
346
+ if (choice) void snackbar.show(t("gallery.overlays.chose", { choice }));
347
+ }
348
+
349
+ async function confirm() {
350
+ const confirmed = await dialog.confirm({
351
+ headline: t("gallery.overlays.dialogTitle"),
352
+ text: t("gallery.overlays.dialogText"),
353
+ confirmLabel: t("gallery.overlays.delete"),
354
+ dismissLabel: t("gallery.overlays.cancel"),
355
+ icon: markRaw(DeleteIcon),
356
+ destructive: true,
357
+ });
358
+ void snackbar.show(confirmed ? t("gallery.overlays.deleted") : t("gallery.overlays.kept"));
359
+ }
360
+
361
+ async function archive() {
362
+ const result = await snackbar.show({
363
+ message: t("gallery.overlays.archived"),
364
+ action: t("gallery.overlays.undo"),
365
+ });
366
+ if (result === "action") void snackbar.show(t("gallery.overlays.restored"));
367
+ }
368
+ </script>
@@ -0,0 +1,175 @@
1
+ <template>
2
+ <GalleryBlock :title="t('gallery.pickers.modal')" :note="t('gallery.pickers.modalNote')">
3
+ <M3Button variant="tonal" @click="dateOpen = true">
4
+ <template #icon><i-ms-calendar-today-outline-rounded /></template>
5
+ {{ date ? formatted(date) : t("gallery.pickers.pick") }}
6
+ </M3Button>
7
+ <M3DatePicker v-model="date" v-model:open="dateOpen" v-bind="dateLabels" :locale="locale" />
8
+ </GalleryBlock>
9
+
10
+ <GalleryBlock :title="t('gallery.pickers.sheet')" :note="t('gallery.pickers.sheetNote')">
11
+ <M3Button variant="tonal" @click="sheetOpen = true">
12
+ <template #icon><i-ms-event-upcoming-outline-rounded /></template>
13
+ {{ sheetDate ? formatted(sheetDate) : t("gallery.pickers.pick") }}
14
+ </M3Button>
15
+ <M3DatePicker
16
+ v-model="sheetDate"
17
+ v-model:open="sheetOpen"
18
+ presentation="sheet"
19
+ v-bind="dateLabels"
20
+ :locale="locale"
21
+ />
22
+ </GalleryBlock>
23
+
24
+ <GalleryBlock :title="t('gallery.pickers.time')" :note="t('gallery.pickers.timeNote')">
25
+ <M3Button variant="tonal" @click="timeOpen = true">
26
+ <template #icon><i-ms-schedule-outline-rounded /></template>
27
+ {{ time ? formatIsoTime(time, locale) : t("gallery.pickers.pickTime") }}
28
+ </M3Button>
29
+ <M3TimePicker v-model="time" v-model:open="timeOpen" v-bind="timeLabels" :locale="locale" />
30
+ </GalleryBlock>
31
+
32
+ <GalleryBlock :title="t('gallery.pickers.timeSheet')" :note="t('gallery.pickers.timeSheetNote')">
33
+ <M3Button variant="tonal" @click="timeSheetOpen = true">
34
+ <template #icon><i-ms-alarm-outline-rounded /></template>
35
+ {{ sheetTime ? formatIsoTime(sheetTime, locale) : t("gallery.pickers.pickTime") }}
36
+ </M3Button>
37
+ <M3TimePicker
38
+ v-model="sheetTime"
39
+ v-model:open="timeSheetOpen"
40
+ presentation="sheet"
41
+ :minute-step="15"
42
+ v-bind="timeLabels"
43
+ :locale="locale"
44
+ />
45
+ </GalleryBlock>
46
+
47
+ <GalleryBlock :title="t('gallery.pickers.docked')" :note="t('gallery.pickers.dockedNote')" stack>
48
+ <div class="overflow-hidden rounded-lg bg-surface-container-high">
49
+ <M3Calendar v-model:value="inline" :min="today" :locale="locale" :is-disabled="isSunday" />
50
+ </div>
51
+ </GalleryBlock>
52
+
53
+ <GalleryBlock :title="t('gallery.pickers.range')" :note="t('gallery.pickers.rangeNote')" stack>
54
+ <div class="overflow-hidden rounded-lg bg-surface-container-high">
55
+ <M3Calendar v-model:start="start" v-model:end="end" mode="range" :locale="locale" />
56
+ </div>
57
+ <p class="type-body-medium m-0 text-on-surface-variant">
58
+ {{ start ? formatted(start) : "—" }} → {{ end ? formatted(end) : "—" }}
59
+ </p>
60
+ </GalleryBlock>
61
+
62
+ <GalleryBlock
63
+ :title="t('gallery.pickers.dateWheel')"
64
+ :note="t('gallery.pickers.dateWheelNote')"
65
+ stack
66
+ >
67
+ <div class="rounded-lg bg-surface-container-low py-2">
68
+ <M3DateWheel
69
+ v-model="wheelDate"
70
+ :locale="locale"
71
+ :label="t('gallery.pickers.dateWheel')"
72
+ :labels="{
73
+ day: t('gallery.pickers.day'),
74
+ month: t('gallery.pickers.month'),
75
+ year: t('gallery.pickers.year'),
76
+ }"
77
+ :rows="5"
78
+ />
79
+ </div>
80
+ <p class="type-body-medium m-0 text-on-surface-variant">
81
+ {{ wheelDate ? formatted(wheelDate) : "—" }}
82
+ </p>
83
+ </GalleryBlock>
84
+
85
+ <GalleryBlock :title="t('gallery.pickers.wheel')" :note="t('gallery.pickers.wheelNote')" stack>
86
+ <div class="rounded-lg bg-surface-container-low py-2">
87
+ <M3WheelPicker v-model="quantity" :columns="quantityColumns" :rows="5" />
88
+ </div>
89
+ </GalleryBlock>
90
+ </template>
91
+
92
+ <script setup lang="ts">
93
+ import {
94
+ addDays,
95
+ formatIso,
96
+ formatIsoTime,
97
+ todayIso,
98
+ weekday,
99
+ type IsoDate,
100
+ type IsoTime,
101
+ type WheelColumn,
102
+ type WheelValue,
103
+ } from "@cavulsqa/m3e-vue";
104
+ import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
105
+
106
+ const { t, locale } = useI18n();
107
+ const today = todayIso();
108
+ const date = ref<IsoDate | null>(null);
109
+ const dateOpen = ref(false);
110
+ const sheetDate = ref<IsoDate | null>(null);
111
+ const sheetOpen = ref(false);
112
+ const time = ref<IsoTime | null>(null);
113
+ const timeOpen = ref(false);
114
+ const sheetTime = ref<IsoTime | null>(null);
115
+ const timeSheetOpen = ref(false);
116
+ const isSunday = (value: IsoDate) => weekday(value) === 0;
117
+ const inline = ref<IsoDate | null>(isSunday(today) ? addDays(today, 1) : today);
118
+ const start = ref<IsoDate | null>(null);
119
+ const end = ref<IsoDate | null>(null);
120
+ const wheelDate = ref<IsoDate | null>(null);
121
+ const quantity = ref<Record<string, WheelValue>>({ count: 12, unit: "box" });
122
+
123
+ const dateLabels = computed(() => ({
124
+ title: t("gallery.pickers.selectDate"),
125
+ emptyHeadline: t("gallery.pickers.selectedDate"),
126
+ confirmLabel: t("gallery.pickers.ok"),
127
+ dismissLabel: t("gallery.overlays.cancel"),
128
+ inputLabel: t("gallery.pickers.typeDate"),
129
+ calendarLabel: t("gallery.pickers.useCalendar"),
130
+ wheelLabel: t("gallery.pickers.useWheel"),
131
+ invalidLabel: t("gallery.pickers.invalid"),
132
+ }));
133
+
134
+ const timeLabels = computed(() => ({
135
+ title: t("gallery.pickers.selectTime"),
136
+ confirmLabel: t("gallery.pickers.ok"),
137
+ dismissLabel: t("gallery.overlays.cancel"),
138
+ dialLabel: t("gallery.pickers.useDial"),
139
+ inputLabel: t("gallery.pickers.useKeyboard"),
140
+ wheelLabel: t("gallery.pickers.useWheel"),
141
+ hourLabel: t("gallery.pickers.hour"),
142
+ minuteLabel: t("gallery.pickers.minute"),
143
+ periodLabel: t("gallery.pickers.period"),
144
+ }));
145
+
146
+ const quantityColumns = computed<WheelColumn[]>(() => [
147
+ {
148
+ key: "count",
149
+ label: t("gallery.pickers.quantity"),
150
+ align: "end",
151
+ options: Array.from({ length: 100 }, (_, index) => ({
152
+ value: index + 1,
153
+ label: String(index + 1),
154
+ })),
155
+ },
156
+ {
157
+ key: "unit",
158
+ label: t("gallery.pickers.unit"),
159
+ align: "start",
160
+ flex: 1.4,
161
+ options: (["box", "pack", "pallet"] as const).map((unit) => ({
162
+ value: unit,
163
+ label: t(`gallery.pickers.units.${unit}`),
164
+ })),
165
+ },
166
+ ]);
167
+
168
+ const formatted = (value: IsoDate) =>
169
+ formatIso(value, locale.value, {
170
+ weekday: "short",
171
+ day: "numeric",
172
+ month: "short",
173
+ year: "numeric",
174
+ });
175
+ </script>
@@ -0,0 +1,118 @@
1
+ <template>
2
+ <GalleryBlock :title="t('gallery.progress.drive')" :note="t('gallery.progress.driveNote')">
3
+ <M3Slider
4
+ v-model="percent"
5
+ class="w-full"
6
+ :label="t('gallery.progress.drive')"
7
+ :format="(v) => `${v}%`"
8
+ />
9
+ </GalleryBlock>
10
+
11
+ <GalleryBlock
12
+ :title="t('gallery.progress.skeleton')"
13
+ :note="t('gallery.progress.skeletonNote')"
14
+ stack
15
+ >
16
+ <div class="flex flex-wrap items-center gap-2">
17
+ <M3Chip
18
+ v-for="option in EFFECTS"
19
+ :key="option"
20
+ kind="filter"
21
+ :label="t(`gallery.progress.${option}`)"
22
+ :selected="effect === option"
23
+ @update:selected="effect = option"
24
+ />
25
+ <M3Button class="ms-auto" variant="tonal" size="s" :disabled="loading" @click="reload">{{
26
+ t("gallery.progress.reload")
27
+ }}</M3Button>
28
+ </div>
29
+ <M3Skeleton
30
+ v-if="loading"
31
+ class="flex flex-col gap-4 [--m3-skeleton-surface:var(--md-sys-color-surface-container-low)]"
32
+ :effect="effect"
33
+ :label="t('gallery.progress.loadingCustomers')"
34
+ >
35
+ <div v-for="row in 3" :key="row" class="flex items-center gap-4">
36
+ <M3SkeletonBlock shape="circle" :width="40" />
37
+ <div class="flex flex-1 flex-col">
38
+ <M3SkeletonText :lines="1" typescale="body-large" width="45%" />
39
+ <M3SkeletonText :lines="1" typescale="body-medium" width="30%" />
40
+ </div>
41
+ </div>
42
+ </M3Skeleton>
43
+ <div v-else class="flex flex-col gap-4">
44
+ <div v-for="row in 3" :key="row" class="flex items-center gap-4">
45
+ <M3Shape
46
+ shape="cookie9Sided"
47
+ class="size-10 bg-primary-container text-on-primary-container"
48
+ >
49
+ <span class="type-title-medium grid size-full place-items-center">{{ row }}</span>
50
+ </M3Shape>
51
+ <div class="flex flex-col">
52
+ <span class="type-body-large text-on-surface">{{
53
+ t("gallery.progress.customer", { n: row })
54
+ }}</span>
55
+ <span class="type-body-medium text-on-surface-variant">{{
56
+ t("gallery.progress.customerNote", { count: row * 2 })
57
+ }}</span>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </GalleryBlock>
62
+
63
+ <GalleryBlock :title="t('gallery.progress.loading')" :note="t('gallery.progress.loadingNote')">
64
+ <M3LoadingIndicator :label="t('gallery.loading')" />
65
+ <M3LoadingIndicator contained :label="t('gallery.loading')" />
66
+ <M3LoadingIndicator :progress="value" :label="t('gallery.progress.determinate')" />
67
+ <M3LoadingIndicator contained :size="72" :label="t('gallery.loading')" />
68
+ </GalleryBlock>
69
+
70
+ <GalleryBlock
71
+ :title="t('gallery.progress.linear')"
72
+ :note="t('gallery.progress.linearNote')"
73
+ stack
74
+ >
75
+ <M3LinearProgress :value="value" :label="t('gallery.progress.determinate')" />
76
+ <M3LinearProgress :label="t('gallery.progress.indeterminate')" />
77
+ <M3LinearProgress :value="value" :wavy="false" :label="t('gallery.progress.flat')" />
78
+ <M3LinearProgress :value="value" :thickness="8" :label="t('gallery.progress.thick')" />
79
+ </GalleryBlock>
80
+
81
+ <GalleryBlock :title="t('gallery.progress.circular')" :note="t('gallery.progress.circularNote')">
82
+ <M3CircularProgress :value="value" :label="t('gallery.progress.determinate')">{{
83
+ percent
84
+ }}</M3CircularProgress>
85
+ <M3CircularProgress :label="t('gallery.progress.indeterminate')" />
86
+ <M3CircularProgress :value="value" :wavy="false" :label="t('gallery.progress.flat')" />
87
+ <M3CircularProgress
88
+ :value="value"
89
+ gauge
90
+ :size="120"
91
+ :thickness="8"
92
+ :label="t('gallery.progress.gauge')"
93
+ >
94
+ <span class="type-title-large-emphasized pt-8">{{ percent }}%</span>
95
+ </M3CircularProgress>
96
+ </GalleryBlock>
97
+ </template>
98
+
99
+ <script setup lang="ts">
100
+ import GalleryBlock from "@/modules/gallery/components/GalleryBlock.vue";
101
+
102
+ const { t } = useI18n();
103
+ const percent = ref(62);
104
+ const EFFECTS = ["wave", "pulse"] as const;
105
+ const effect = ref<(typeof EFFECTS)[number]>("wave");
106
+ const loading = ref(true);
107
+ let timer: ReturnType<typeof setTimeout> | undefined;
108
+
109
+ function reload() {
110
+ loading.value = true;
111
+ clearTimeout(timer);
112
+ timer = setTimeout(() => (loading.value = false), 2400);
113
+ }
114
+
115
+ onMounted(reload);
116
+ onBeforeUnmount(() => clearTimeout(timer));
117
+ const value = computed(() => percent.value / 100);
118
+ </script>