@bettertogether/community-engine-vue 0.1.7 → 0.2.2

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 (230) hide show
  1. package/README.md +140 -1
  2. package/dist/assets/BBadge.vue_vue_type_script_setup_true_lang-IIZ8QpjG-Z9WDKHqT.js +1 -0
  3. package/dist/assets/BCardText.vue_vue_type_script_setup_true_lang-Be6CD36N-B5JCTdmm.js +3 -0
  4. package/dist/assets/BFormSelect.vue_vue_type_script_setup_true_lang-BigptVap-B_HbOOZR.js +1 -0
  5. package/dist/assets/BRow.vue_vue_type_script_setup_true_lang-69TY75-8-DJdEdyx7.js +1 -0
  6. package/dist/assets/Communities-Cx4tT-bx.js +1 -0
  7. package/dist/assets/Communities-n33ssuUH.css +1 -0
  8. package/dist/assets/CommunityConversation-bBkYBs2k.css +1 -0
  9. package/dist/assets/CommunityConversation-jHAnv_Ps.js +1 -0
  10. package/dist/assets/CommunityConversations-rEDGS7To.js +1 -0
  11. package/dist/assets/CommunityEvent-CUdT0aT4.js +1 -0
  12. package/dist/assets/CommunityEvents-rsOgcxQr.js +1 -0
  13. package/dist/assets/CommunityHome-ChuTE2Nz.js +1 -0
  14. package/dist/assets/CommunityJoaTu-CpLIY_83.js +1 -0
  15. package/dist/assets/CommunityMembers-C3UtzQGp.css +1 -0
  16. package/dist/assets/CommunityMembers-DKf74ltl.js +1 -0
  17. package/dist/assets/CommunityPage-C5x23iQl.css +1 -0
  18. package/dist/assets/CommunityPage-CRYg9-rW.js +1 -0
  19. package/dist/assets/CommunityPages-IsLTNFC3.js +1 -0
  20. package/dist/assets/CommunityPost-BOnqqxVs.js +1 -0
  21. package/dist/assets/CommunityPost-BRYtkDSY.css +1 -0
  22. package/dist/assets/CommunityPosts-DY1olmcU.js +1 -0
  23. package/dist/assets/Error404-D10VQARe.js +1 -0
  24. package/dist/assets/EventCard-vfutXTdg.js +1 -0
  25. package/dist/assets/EventList-ChtehYcJ.js +1 -0
  26. package/dist/assets/ExtensionSlot-DJKbrq4c.js +1 -0
  27. package/dist/assets/PostList-BuHrBBqX.css +1 -0
  28. package/dist/assets/PostList-DYFgxlE8.js +1 -0
  29. package/dist/assets/SyncBadge-B1JBsdUk.js +1 -0
  30. package/dist/assets/SyncBadge-FNO-QLuu.css +1 -0
  31. package/dist/assets/UserPasswordNew-D_Djldm9.css +1 -0
  32. package/dist/assets/UserPasswordNew-al9bNBTZ.js +1 -0
  33. package/dist/assets/UserPasswordReset-42zs98RW.js +1 -0
  34. package/dist/assets/UserPasswordReset-D_6OQDZY.css +1 -0
  35. package/dist/assets/UserResendConfirmation-CGavYB81.js +1 -0
  36. package/dist/assets/UserResendConfirmation-DNTHcaar.css +1 -0
  37. package/dist/assets/UserSignIn-BIRb0HkV.js +1 -0
  38. package/dist/assets/UserSignIn-C-Pol8OD.css +1 -0
  39. package/dist/assets/UserSignUp-ChkKQAd2.css +1 -0
  40. package/dist/assets/UserSignUp-Df6o3vlO.js +1 -0
  41. package/dist/assets/better-together-logo-61cxo5d5.png +0 -0
  42. package/dist/assets/index-BFt-JKVh.css +5 -0
  43. package/dist/assets/index-COo3Jb7v.js +1088 -0
  44. package/dist/assets/nodefs-Bfyh92qg.js +1 -0
  45. package/dist/assets/opfs-ahp-BLzlXf6u.js +3 -0
  46. package/dist/assets/pglite-BdRI_ZYT.wasm +0 -0
  47. package/dist/assets/pglite-COscPi1Y.data +0 -0
  48. package/dist/assets/usePages-DDjDQRCy.js +1 -0
  49. package/dist/assets/usePosts-Bf2Ccwr4.js +1 -0
  50. package/{public → dist}/index.html +9 -19
  51. package/package.json +57 -45
  52. package/src/BtApp.vue +34 -43
  53. package/src/components/BtBrandingLogo.vue +10 -18
  54. package/src/components/BtHeader.vue +31 -89
  55. package/src/components/BtMainContent.vue +12 -43
  56. package/src/components/BtNavBar.vue +25 -38
  57. package/src/components/BtNavItem.vue +25 -58
  58. package/src/components/BtNavUser.vue +65 -86
  59. package/src/components/BtProfileForm.vue +48 -39
  60. package/src/components/BtUserNewPasswordForm.vue +52 -74
  61. package/src/components/BtUserResendConfirmationForm.vue +45 -83
  62. package/src/components/BtUserResetPasswordForm.vue +45 -77
  63. package/src/components/BtUserSignInForm.vue +59 -75
  64. package/src/components/BtUserSignUpForm.vue +90 -103
  65. package/src/components/CommunityForm.vue +47 -39
  66. package/src/components/community/CommunityCard.vue +113 -0
  67. package/src/components/community/CommunityHeader.vue +91 -0
  68. package/src/components/community/CommunityList.vue +59 -0
  69. package/src/components/community/MemberRoleRow.vue +107 -0
  70. package/src/components/conversation/ConversationCard.vue +49 -0
  71. package/src/components/conversation/ConversationDetail.vue +53 -0
  72. package/src/components/conversation/ConversationList.vue +51 -0
  73. package/src/components/conversation/MessageForm.vue +45 -0
  74. package/src/components/conversation/MessageItem.vue +43 -0
  75. package/src/components/conversation/MessageList.vue +39 -0
  76. package/src/components/event/EventCard.vue +82 -0
  77. package/src/components/event/EventForm.vue +99 -0
  78. package/src/components/event/EventList.vue +47 -0
  79. package/src/components/invitation/InvitationCard.vue +56 -0
  80. package/src/components/invitation/InvitationForm.vue +70 -0
  81. package/src/components/invitation/InvitationList.vue +51 -0
  82. package/src/components/joatu/AgreementCard.vue +57 -0
  83. package/src/components/joatu/AgreementList.vue +51 -0
  84. package/src/components/joatu/OfferCard.vue +65 -0
  85. package/src/components/joatu/OfferForm.vue +82 -0
  86. package/src/components/joatu/OfferList.vue +51 -0
  87. package/src/components/joatu/RequestCard.vue +65 -0
  88. package/src/components/joatu/RequestForm.vue +82 -0
  89. package/src/components/joatu/RequestList.vue +51 -0
  90. package/src/components/page/PageCard.vue +55 -0
  91. package/src/components/page/PageDetail.vue +35 -0
  92. package/src/components/page/PageList.vue +51 -0
  93. package/src/components/person/MemberList.vue +61 -0
  94. package/src/components/person/PersonAvatar.vue +54 -0
  95. package/src/components/person/PersonCard.vue +47 -0
  96. package/src/components/post/PostCard.vue +105 -0
  97. package/src/components/post/PostDetail.vue +98 -0
  98. package/src/components/post/PostForm.vue +84 -0
  99. package/src/components/post/PostList.vue +53 -0
  100. package/src/components/role/BlockButton.vue +44 -0
  101. package/src/components/role/RoleBadge.vue +19 -0
  102. package/src/components/role/RoleGate.vue +62 -0
  103. package/src/components/role/RoleSelector.vue +29 -0
  104. package/src/components/shared/ExtensionSlot.vue +27 -0
  105. package/src/components/sync/OfflineBanner.vue +49 -0
  106. package/src/components/sync/SyncBadge.vue +108 -0
  107. package/src/components/sync/SyncStatusBar.vue +121 -0
  108. package/src/composables/useCommunities.js +19 -0
  109. package/src/composables/useConversations.js +5 -0
  110. package/src/composables/useEvents.js +28 -0
  111. package/src/composables/useInvitations.js +10 -0
  112. package/src/composables/useJoaTuAgreements.js +11 -0
  113. package/src/composables/useJoaTuOffers.js +10 -0
  114. package/src/composables/useJoaTuRequests.js +10 -0
  115. package/src/composables/useMembers.js +30 -0
  116. package/src/composables/useMessages.js +5 -0
  117. package/src/composables/useNotifications.js +5 -0
  118. package/src/composables/usePages.js +6 -0
  119. package/src/composables/usePersonBlocks.js +65 -0
  120. package/src/composables/usePosts.js +27 -0
  121. package/src/composables/useResource.js +137 -0
  122. package/src/composables/useRoles.js +94 -0
  123. package/src/composables/useSyncStatus.js +22 -0
  124. package/src/composables/useToaster.js +20 -0
  125. package/src/context.js +18 -0
  126. package/src/db/client.js +343 -0
  127. package/src/db/migrations/001_initial.sql +131 -0
  128. package/src/db/migrations/003_conversations_invitations_pages_joatu.sql +76 -0
  129. package/src/db/sync.js +276 -0
  130. package/src/endpoints/BtApiAuth.js +1 -1
  131. package/src/endpoints/BtApiV1.js +1 -1
  132. package/src/extension.js +45 -0
  133. package/src/i18n/index.js +103 -0
  134. package/src/i18n/locales/en.json +275 -0
  135. package/src/i18n/locales/es.json +275 -0
  136. package/src/i18n/locales/fr.json +223 -0
  137. package/src/i18n/locales/uk.json +275 -0
  138. package/src/index.js +168 -22
  139. package/src/layouts/CommunityLayout.vue +89 -0
  140. package/src/main.js +16 -12
  141. package/src/mixins/error-handling.js +6 -15
  142. package/src/mixins/toaster.js +15 -10
  143. package/src/pages/Communities.vue +59 -0
  144. package/src/pages/Error404.vue +10 -14
  145. package/src/pages/Home.vue +11 -18
  146. package/src/pages/Me.vue +39 -59
  147. package/src/pages/UserPasswordNew.vue +12 -68
  148. package/src/pages/UserPasswordReset.vue +15 -64
  149. package/src/pages/UserResendConfirmation.vue +39 -113
  150. package/src/pages/UserSignIn.vue +18 -67
  151. package/src/pages/UserSignUp.vue +15 -64
  152. package/src/pages/community/CommunityConversation.vue +31 -0
  153. package/src/pages/community/CommunityConversations.vue +18 -0
  154. package/src/pages/community/CommunityEvent.vue +39 -0
  155. package/src/pages/community/CommunityEvents.vue +58 -0
  156. package/src/pages/community/CommunityHome.vue +49 -0
  157. package/src/pages/community/CommunityJoaTu.vue +115 -0
  158. package/src/pages/community/CommunityMembers.vue +23 -0
  159. package/src/pages/community/CommunityPage.vue +31 -0
  160. package/src/pages/community/CommunityPages.vue +25 -0
  161. package/src/pages/community/CommunityPost.vue +28 -0
  162. package/src/pages/community/CommunityPosts.vue +58 -0
  163. package/src/pages/community/CommunitySettingsPage.vue +117 -0
  164. package/src/pages/community/RoleManagerPage.vue +93 -0
  165. package/src/plugins/bootstrap-vue.js +5 -5
  166. package/src/plugins/font-awesome.js +3 -2
  167. package/src/plugins/index.js +9 -4
  168. package/src/plugins/progress.js +16 -0
  169. package/src/pwa/index.js +156 -0
  170. package/src/pwa/sw-helpers.js +130 -0
  171. package/src/router/communityRoutes.js +78 -0
  172. package/src/router/index.js +30 -144
  173. package/src/slot-registry.js +15 -0
  174. package/src/stores/auth.js +134 -0
  175. package/src/stores/communities.js +59 -0
  176. package/src/stores/index.js +5 -0
  177. package/src/stores/menus.js +14 -0
  178. package/src/stores/people.js +48 -0
  179. package/src/stores/sync.js +93 -0
  180. package/src/stylesheets/sync-indicators.scss +34 -0
  181. package/.env.sample +0 -1
  182. package/.eslintrc.js +0 -51
  183. package/.gitlab-ci.yml +0 -14
  184. package/.travis/.rbenv-gemsets +0 -1
  185. package/.travis/.ruby-version +0 -1
  186. package/.travis.yml +0 -31
  187. package/babel.config.js +0 -5
  188. package/cypress.json +0 -3
  189. package/deploy/build.sh +0 -8
  190. package/eslint.config.js +0 -16
  191. package/postcss.config.js +0 -5
  192. package/src/eslint.config.js +0 -16
  193. package/src/forms/BtProfileFormSchema.js +0 -19
  194. package/src/forms/BtUserConfirmationFormSchema.js +0 -20
  195. package/src/forms/BtUserNewPasswordFormSchema.js +0 -29
  196. package/src/forms/BtUserResetPasswordFormSchema.js +0 -20
  197. package/src/forms/BtUserSignInFormSchema.js +0 -29
  198. package/src/forms/BtUserSignUpFormSchema.js +0 -63
  199. package/src/forms/CommunityFormSchema.js +0 -19
  200. package/src/plugins/vue-form-generator.js +0 -4
  201. package/src/plugins/vue-loading.js +0 -10
  202. package/src/registerServiceWorker.js +0 -32
  203. package/src/store/index.js +0 -32
  204. package/src/store/modules/authentication.js +0 -170
  205. package/src/store/modules/communities.js +0 -98
  206. package/src/store/modules/community-engine.js +0 -14
  207. package/src/store/modules/menus.js +0 -52
  208. package/src/store/modules/people.js +0 -88
  209. package/src/vue.config.js +0 -0
  210. package/tests/e2e/.eslintrc.js +0 -12
  211. package/tests/e2e/plugins/index.js +0 -26
  212. package/tests/e2e/specs/home.js +0 -8
  213. package/tests/e2e/support/commands.js +0 -25
  214. package/tests/e2e/support/index.js +0 -20
  215. package/tests/unit/.eslintrc.js +0 -5
  216. package/tests/unit/example.spec.js +0 -13
  217. package/vue.config.js +0 -11
  218. package/webpack.config.js +0 -28
  219. /package/{public → dist}/_redirects +0 -0
  220. /package/{public → dist}/favicon.ico +0 -0
  221. /package/{public → dist}/img/favicon.ico +0 -0
  222. /package/{public → dist}/img/icons/android-chrome-192x192.png +0 -0
  223. /package/{public → dist}/img/icons/android-chrome-384x384.png +0 -0
  224. /package/{public → dist}/img/icons/apple-touch-icon.png +0 -0
  225. /package/{public → dist}/img/icons/favicon-16x16.png +0 -0
  226. /package/{public → dist}/img/icons/favicon-32x32.png +0 -0
  227. /package/{public → dist}/img/icons/favicon.ico +0 -0
  228. /package/{public → dist}/img/icons/mstile-150x150.png +0 -0
  229. /package/{public → dist}/img/icons/safari-pinned-tab.svg +0 -0
  230. /package/{public → dist}/robots.txt +0 -0
package/src/index.js CHANGED
@@ -1,45 +1,191 @@
1
- import './plugins'
2
1
  import { library } from '@fortawesome/fontawesome-svg-core'
3
2
  import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'
4
3
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
5
4
 
6
5
  import BtRouter, { BtRoutes } from './router'
7
- import BtStore, { BtStoreModules, BtStorePlugins } from './store'
8
6
 
9
7
  import BtHeader from './components/BtHeader.vue'
10
8
  import BtMainContent from './components/BtMainContent.vue'
11
9
  import BtNavBar from './components/BtNavBar.vue'
12
10
  import BtNavItem from './components/BtNavItem.vue'
13
11
  import BtNavUser from './components/BtNavUser.vue'
14
-
15
12
  import BtUserNewPasswordForm from './components/BtUserNewPasswordForm.vue'
16
13
  import BtUserResendConfirmationForm from './components/BtUserResendConfirmationForm.vue'
17
14
  import BtUserResetPasswordForm from './components/BtUserResetPasswordForm.vue'
18
15
  import BtUserSignInForm from './components/BtUserSignInForm.vue'
19
16
  import BtUserSignUpForm from './components/BtUserSignUpForm.vue'
17
+ import SyncBadge from './components/sync/SyncBadge.vue'
18
+ import SyncStatusBar from './components/sync/SyncStatusBar.vue'
19
+ import OfflineBanner from './components/sync/OfflineBanner.vue'
20
+ import ExtensionSlot from './components/shared/ExtensionSlot.vue'
21
+
22
+ import { setCevContext } from './context'
23
+ import { installI18n } from './i18n'
24
+ import { getDb } from './db/client'
25
+ import { startSync } from './db/sync'
26
+ import CommunityCard from './components/community/CommunityCard.vue'
27
+ import CommunityList from './components/community/CommunityList.vue'
28
+ import CommunityHeader from './components/community/CommunityHeader.vue'
29
+ import PersonCard from './components/person/PersonCard.vue'
30
+ import PersonAvatar from './components/person/PersonAvatar.vue'
31
+ import MemberList from './components/person/MemberList.vue'
32
+ import PostCard from './components/post/PostCard.vue'
33
+ import PostList from './components/post/PostList.vue'
34
+ import PostForm from './components/post/PostForm.vue'
35
+ import PostDetail from './components/post/PostDetail.vue'
36
+ import EventCard from './components/event/EventCard.vue'
37
+ import EventList from './components/event/EventList.vue'
38
+ import EventForm from './components/event/EventForm.vue'
39
+ import ConversationCard from './components/conversation/ConversationCard.vue'
40
+ import ConversationList from './components/conversation/ConversationList.vue'
41
+ import ConversationDetail from './components/conversation/ConversationDetail.vue'
42
+ import MessageItem from './components/conversation/MessageItem.vue'
43
+ import MessageList from './components/conversation/MessageList.vue'
44
+ import MessageForm from './components/conversation/MessageForm.vue'
45
+ import InvitationCard from './components/invitation/InvitationCard.vue'
46
+ import InvitationList from './components/invitation/InvitationList.vue'
47
+ import InvitationForm from './components/invitation/InvitationForm.vue'
48
+ import PageCard from './components/page/PageCard.vue'
49
+ import PageList from './components/page/PageList.vue'
50
+ import PageDetail from './components/page/PageDetail.vue'
51
+ import OfferCard from './components/joatu/OfferCard.vue'
52
+ import OfferList from './components/joatu/OfferList.vue'
53
+ import OfferForm from './components/joatu/OfferForm.vue'
54
+ import RequestCard from './components/joatu/RequestCard.vue'
55
+ import RequestList from './components/joatu/RequestList.vue'
56
+ import RequestForm from './components/joatu/RequestForm.vue'
57
+ import AgreementCard from './components/joatu/AgreementCard.vue'
58
+ import AgreementList from './components/joatu/AgreementList.vue'
59
+ import RoleGate from './components/role/RoleGate.vue'
60
+ import BlockButton from './components/role/BlockButton.vue'
61
+ import RoleBadge from './components/role/RoleBadge.vue'
62
+ import RoleSelector from './components/role/RoleSelector.vue'
63
+ import MemberRoleRow from './components/community/MemberRoleRow.vue'
64
+
65
+ export {
66
+ useAuthStore,
67
+ useCommunityStore,
68
+ useMenuStore,
69
+ usePeopleStore,
70
+ useSyncStore,
71
+ } from './stores'
72
+
73
+ export { getDb, registerExtensionMigration } from './db/client'
74
+ export { startSync } from './db/sync'
75
+
76
+ export { useResource } from './composables/useResource'
77
+ export { usePosts } from './composables/usePosts'
78
+ export { useEvents } from './composables/useEvents'
79
+ export { useConversations } from './composables/useConversations'
80
+ export { useMessages } from './composables/useMessages'
81
+ export { useInvitations } from './composables/useInvitations'
82
+ export { usePages } from './composables/usePages'
83
+ export { useRoles } from './composables/useRoles'
84
+ export { usePersonBlocks } from './composables/usePersonBlocks'
85
+ export { useJoaTuOffers } from './composables/useJoaTuOffers'
86
+ export { useJoaTuRequests } from './composables/useJoaTuRequests'
87
+ export { useJoaTuAgreements } from './composables/useJoaTuAgreements'
88
+ export { useMembers } from './composables/useMembers'
89
+ export { useNotifications } from './composables/useNotifications'
90
+ export { useSyncStatus } from './composables/useSyncStatus'
91
+
92
+ export { getCevContext } from './context'
93
+ export { defineExtension } from './extension'
94
+ export { registerSlotInjection, getSlotInjections } from './slot-registry'
95
+ export { createCevI18n, installI18n, registerExtensionMessages } from './i18n'
96
+ export { useI18n } from 'vue-i18n'
97
+
98
+ export { useCommunities } from './composables/useCommunities'
99
+ export { communityRoutes } from './router/communityRoutes'
100
+ export {
101
+ CommunityCard,
102
+ CommunityList,
103
+ CommunityHeader,
104
+ PersonCard,
105
+ PersonAvatar,
106
+ MemberList,
107
+ PostCard,
108
+ PostList,
109
+ PostForm,
110
+ PostDetail,
111
+ EventCard,
112
+ EventList,
113
+ EventForm,
114
+ ConversationCard, ConversationList, ConversationDetail,
115
+ MessageItem, MessageList, MessageForm,
116
+ InvitationCard, InvitationList, InvitationForm,
117
+ PageCard, PageList, PageDetail,
118
+ OfferCard, OfferList, OfferForm,
119
+ RequestCard, RequestList, RequestForm,
120
+ AgreementCard, AgreementList,
121
+ RoleGate, BlockButton,
122
+ RoleBadge, RoleSelector, MemberRoleRow,
123
+ }
20
124
 
21
125
  library.add(faExternalLinkAlt)
22
126
 
23
127
  const NAME = 'CommunityEngineVue'
24
128
 
25
- const install = (Vue) => {
26
- Vue.component('FontAwesomeIcon', FontAwesomeIcon)
27
- Vue.component('BtNavUser', BtNavUser)
28
- Vue.component('BtUserNewPasswordForm', BtUserNewPasswordForm)
29
- }
129
+ const install = (app, options = {}) => {
130
+ app.component('FontAwesomeIcon', FontAwesomeIcon)
131
+ app.component('BtNavUser', BtNavUser)
132
+ app.component('BtUserNewPasswordForm', BtUserNewPasswordForm)
133
+ app.component('ExtensionSlot', ExtensionSlot)
30
134
 
31
- // --- CommunityEngineVue plugin ---
32
- const CommunityEngineVue = /* #__PURE__ */ {
33
- install,
34
- NAME,
35
- }
135
+ // Install vue-i18n (merges into host app's i18n instance if one exists)
136
+ installI18n(app, options)
36
137
 
37
- export {
38
- install,
39
- NAME,
40
- CommunityEngineVue,
138
+ // Apply theme CSS custom properties
139
+ if (options.theme) {
140
+ const root = document.documentElement
141
+ const themeMap = {
142
+ primary: '--bt-primary',
143
+ accent: '--bt-accent',
144
+ background: '--bt-background',
145
+ text: '--bt-text',
146
+ fontFamily: '--bt-font-family',
147
+ }
148
+ Object.entries(options.theme).forEach(([k, v]) => {
149
+ if (themeMap[k]) root.style.setProperty(themeMap[k], v)
150
+ })
151
+ }
152
+
153
+ // Store plugin context so extensions and composables can access app + options
154
+ setCevContext({ app, options })
155
+
156
+ // Start Electric sync if configured (graceful no-op when VITE_ELECTRIC_URL unset)
157
+ getDb().then(db => startSync(db)).catch(() => { /* Electric not configured */ })
158
+
159
+ // Install companion extensions
160
+ if (options.extensions?.length) {
161
+ options.extensions.forEach((ext) => {
162
+ if (ext._install) ext._install()
163
+ })
164
+ }
165
+
166
+ app.component('BtCommunityCard', CommunityCard)
167
+ app.component('BtPostCard', PostCard)
168
+ app.component('BtEventCard', EventCard)
169
+ app.component('BtPersonCard', PersonCard)
170
+ app.component('BtPersonAvatar', PersonAvatar)
171
+ app.component('BtConversationCard', ConversationCard)
172
+ app.component('BtMessageItem', MessageItem)
173
+ app.component('BtInvitationCard', InvitationCard)
174
+ app.component('BtPageCard', PageCard)
175
+ app.component('BtOfferCard', OfferCard)
176
+ app.component('BtRequestCard', RequestCard)
177
+ app.component('BtAgreementCard', AgreementCard)
178
+ app.component('RoleGate', RoleGate)
179
+ app.component('BtRoleGate', RoleGate)
180
+ app.component('BtBlockButton', BlockButton)
181
+ app.component('BtRoleBadge', RoleBadge)
182
+ app.component('BtRoleSelector', RoleSelector)
183
+ app.component('BtMemberRoleRow', MemberRoleRow)
41
184
  }
42
185
 
186
+ const CommunityEngineVue = { install, NAME }
187
+
188
+ export { install, NAME, CommunityEngineVue }
43
189
  export {
44
190
  BtHeader,
45
191
  BtMainContent,
@@ -48,15 +194,15 @@ export {
48
194
  BtNavUser,
49
195
  BtRouter,
50
196
  BtRoutes,
51
- BtStore,
52
- BtStoreModules,
53
- BtStorePlugins,
54
197
  BtUserNewPasswordForm,
55
198
  BtUserResendConfirmationForm,
56
199
  BtUserResetPasswordForm,
57
200
  BtUserSignInForm,
58
201
  BtUserSignUpForm,
202
+ SyncBadge,
203
+ SyncStatusBar,
204
+ OfflineBanner,
205
+ ExtensionSlot,
59
206
  }
60
-
61
- // Default export is the CommunityEngineVue plugin
207
+ export { useInstallPrompt, useSwUpdate, getCevWorkboxConfig } from './pwa/index'
62
208
  export default CommunityEngineVue
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <div class="bt-community-layout">
3
+ <div
4
+ v-if="loading"
5
+ class="text-center py-5"
6
+ >
7
+ <BSpinner :label="t('bt.communities.loading')" />
8
+ </div>
9
+ <div
10
+ v-else-if="!community"
11
+ class="container py-5"
12
+ >
13
+ <BAlert
14
+ variant="warning"
15
+ :model-value="true"
16
+ >
17
+ {{ t('bt.communities.not_found') }}
18
+ </BAlert>
19
+ </div>
20
+ <template v-else>
21
+ <CommunityHeader :community="community" />
22
+ <nav class="bt-community-nav bg-light border-bottom">
23
+ <div class="container">
24
+ <ul class="nav nav-pills py-2">
25
+ <li
26
+ v-for="link in communityNav"
27
+ :key="link.name"
28
+ class="nav-item"
29
+ >
30
+ <RouterLink
31
+ :to="{ name: link.name, params: { communitySlug: communitySlug } }"
32
+ class="nav-link"
33
+ active-class="active"
34
+ >
35
+ {{ link.label }}
36
+ </RouterLink>
37
+ </li>
38
+ </ul>
39
+ </div>
40
+ </nav>
41
+ <div class="container py-4">
42
+ <RouterView />
43
+ </div>
44
+ </template>
45
+ </div>
46
+ </template>
47
+
48
+ <script setup>
49
+ import { ref, computed, onMounted, watch } from 'vue'
50
+ import { useI18n } from 'vue-i18n'
51
+ import { useRoute } from 'vue-router'
52
+ import { BSpinner, BAlert } from 'bootstrap-vue-next'
53
+ import { useCommunityStore } from '../stores/communities'
54
+ import { useCommunities } from '../composables/useCommunities'
55
+ import { useRoles } from '../composables/useRoles'
56
+ import CommunityHeader from '../components/community/CommunityHeader.vue'
57
+
58
+ const { t } = useI18n()
59
+ const route = useRoute()
60
+ const communityStore = useCommunityStore()
61
+ const { findBySlug, current: community, loading } = useCommunities()
62
+
63
+ const communitySlug = ref(route.params.communitySlug)
64
+
65
+ const { hasRole } = useRoles('community', communitySlug)
66
+
67
+ const communityNav = computed(() => {
68
+ const links = [
69
+ { name: 'CommunityHome', label: t('bt.navigation.home') },
70
+ { name: 'CommunityPosts', label: t('bt.navigation.posts') },
71
+ { name: 'CommunityEvents', label: t('bt.navigation.events') },
72
+ { name: 'CommunityMembers', label: t('bt.navigation.members') },
73
+ { name: 'CommunityConversations', label: t('bt.navigation.conversations') },
74
+ ]
75
+ if (hasRole('admin')) {
76
+ links.push({ name: 'community-settings', label: t('bt.navigation.settings') })
77
+ }
78
+ return links
79
+ })
80
+
81
+ async function loadCommunity(slug) {
82
+ communitySlug.value = slug
83
+ const c = await findBySlug(slug)
84
+ if (c) communityStore.activeCommunity = c
85
+ }
86
+
87
+ onMounted(() => loadCommunity(route.params.communitySlug))
88
+ watch(() => route.params.communitySlug, (slug) => { if (slug) loadCommunity(slug) })
89
+ </script>
package/src/main.js CHANGED
@@ -1,16 +1,20 @@
1
- import '@babel/polyfill'
2
- import 'mutationobserver-shim'
3
- import Vue from 'vue'
1
+ import { createApp } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4
4
  import BtApp from './BtApp.vue'
5
- import './plugins'
6
- import './registerServiceWorker'
7
5
  import router from './router'
8
- import store from './store'
6
+ import { setupPlugins } from './plugins'
7
+ import { useSyncStore } from './stores/sync'
9
8
 
10
- Vue.config.productionTip = false
9
+ const pinia = createPinia()
10
+ pinia.use(piniaPluginPersistedstate)
11
11
 
12
- new Vue({
13
- router,
14
- store,
15
- render: (h) => h(BtApp),
16
- }).$mount('#app')
12
+ const app = createApp(BtApp)
13
+ app.use(pinia)
14
+ app.use(router)
15
+ setupPlugins(app)
16
+ app.mount('#app')
17
+
18
+ // Initialize network listeners after mount (store is accessible after pinia is installed)
19
+ const syncStore = useSyncStore()
20
+ syncStore.initNetworkListeners()
@@ -1,26 +1,17 @@
1
- import toaster from './toaster'
1
+ import { useToaster } from '../composables/useToaster'
2
2
 
3
3
  export default {
4
- mixins: [
5
- toaster,
6
- ],
7
4
  methods: {
8
5
  $handleResponseError(response) {
6
+ const { toast } = useToaster()
9
7
  const { status } = response
10
8
  let message = ''
11
-
12
9
  switch (status) {
13
- case 401:
14
- message = response.data.error
15
- break
16
- case 500:
17
- message = 'Sorry, there was a server error. Please try again.'
18
- break
19
- default:
20
- message = 'Sorry, there was an error'
10
+ case 401: message = response.data.error; break
11
+ case 500: message = 'Sorry, there was a server error. Please try again.'; break
12
+ default: message = 'Sorry, there was an error'
21
13
  }
22
-
23
- this.$toaster(message, 'danger')
14
+ toast(message, 'danger')
24
15
  },
25
16
  },
26
17
  }
@@ -1,16 +1,21 @@
1
+ import { useToastController } from 'bootstrap-vue-next'
2
+
3
+ // Legacy mixin — kept for Options API components still being migrated.
4
+ // New components should use useToaster() directly.
1
5
  export default {
2
6
  methods: {
3
7
  $toaster(msg, type = null, opts = {}) {
4
- const options = {
5
- variant: type,
6
- solid: true,
7
- autoHideDelay: 2000,
8
- ...opts,
9
- }
10
- this.$bvToast.toast(
11
- msg,
12
- options,
13
- )
8
+ const { show } = useToastController()
9
+ show({
10
+ props: {
11
+ body: msg,
12
+ variant: type,
13
+ solid: true,
14
+ value: opts.autoHideDelay || 2000,
15
+ title: opts.title,
16
+ pos: 'top-end',
17
+ },
18
+ })
14
19
  },
15
20
  },
16
21
  }
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <div class="bt-communities-page">
3
+ <div class="container py-4">
4
+ <div class="d-flex align-items-center justify-content-between mb-4">
5
+ <h1>{{ t('bt.navigation.communities') }}</h1>
6
+ <BButton
7
+ v-if="authStore.isAuthenticated"
8
+ variant="primary"
9
+ @click="showCreateForm = true"
10
+ >
11
+ {{ t('bt.communities.new') }}
12
+ </BButton>
13
+ </div>
14
+
15
+ <CommunityList
16
+ :communities="items"
17
+ :loading="loading"
18
+ @view="goToCommunity"
19
+ />
20
+
21
+ <BModal
22
+ v-model="showCreateForm"
23
+ :title="t('bt.communities.create')"
24
+ @ok.prevent="createCommunity"
25
+ >
26
+ <CommunityForm @submit="createCommunity" />
27
+ </BModal>
28
+ </div>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup>
33
+ import { ref, onMounted } from 'vue'
34
+ import { useI18n } from 'vue-i18n'
35
+ import { useRouter } from 'vue-router'
36
+ import { BButton, BModal } from 'bootstrap-vue-next'
37
+ import { useAuthStore } from '../stores/auth'
38
+ import { useCommunities } from '../composables/useCommunities'
39
+ import CommunityList from '../components/community/CommunityList.vue'
40
+ import CommunityForm from '../components/CommunityForm.vue'
41
+
42
+ const { t } = useI18n()
43
+
44
+ const router = useRouter()
45
+ const authStore = useAuthStore()
46
+ const { items, loading, list, create } = useCommunities()
47
+ const showCreateForm = ref(false)
48
+
49
+ onMounted(() => list())
50
+
51
+ function goToCommunity(community) {
52
+ router.push({ name: 'CommunityHome', params: { communitySlug: community.slug } })
53
+ }
54
+
55
+ async function createCommunity(formData) {
56
+ await create(formData)
57
+ showCreateForm.value = false
58
+ }
59
+ </script>
@@ -3,32 +3,28 @@
3
3
  <div class="row heading mb-3">
4
4
  <div class="col-md">
5
5
  <h2 class="mb-4">
6
- This is not the page you are looking for
6
+ {{ t('bt.errors.not_found_heading') }}
7
7
  </h2>
8
- <p>
9
- Looks like the address that you entered does't match a page on our
10
- site. Perhaps the page has move to a new address. Please try again.
11
- </p>
8
+ <p>{{ t('bt.errors.not_found_message') }}</p>
12
9
  <div class="text-center mt-4">
13
- <router-link
10
+ <RouterLink
14
11
  to="/"
15
- title="Better Together landing page"
12
+ :title="t('bt.app.name')"
16
13
  class="btn btn-primary card-action"
17
14
  >
18
- Visit Landing Page
19
- </router-link>
15
+ {{ t('bt.errors.visit_home') }}
16
+ </RouterLink>
20
17
  </div>
21
18
  </div>
22
19
  </div>
23
20
  </section>
24
21
  </template>
25
22
 
26
- <script>
27
- // @ is an alias to /src
23
+ <script setup>
24
+ import { useI18n } from 'vue-i18n'
25
+ import { RouterLink } from 'vue-router'
28
26
 
29
- export default {
30
- name: 'Error404',
31
- }
27
+ const { t } = useI18n()
32
28
  </script>
33
29
 
34
30
  <style lang="scss">
@@ -1,29 +1,22 @@
1
1
  <template>
2
- <div
3
- id="home"
4
- class=""
5
- >
6
- <section
7
- id="introduction"
8
- >
2
+ <div id="home">
3
+ <section id="introduction">
9
4
  <div class="col">
10
- <h1>Connect with your communities</h1>
11
- <p>
12
- The Community Engine platform allows you to connect with others like never before
13
- </p>
5
+ <h1>{{ t('bt.app.home_heading') }}</h1>
6
+ <p>{{ t('bt.app.home_tagline') }}</p>
14
7
  </div>
15
8
  </section>
16
9
  </div>
17
10
  </template>
18
11
 
19
- <script>
20
- export default {
21
- name: 'Home',
22
- }
12
+ <script setup>
13
+ import { useI18n } from 'vue-i18n'
14
+
15
+ const { t } = useI18n()
23
16
  </script>
24
17
 
25
18
  <style scoped lang="scss">
26
- h2 {
27
- margin-bottom: 1.5rem;
28
- }
19
+ h2 {
20
+ margin-bottom: 1.5rem;
21
+ }
29
22
  </style>