@rebasepro/client-firebase 0.0.1-canary.4d4fb3e

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -0
  3. package/dist/components/FirebaseLoginView.d.ts +72 -0
  4. package/dist/components/RebaseFirebaseApp.d.ts +19 -0
  5. package/dist/components/RebaseFirebaseAppProps.d.ts +144 -0
  6. package/dist/components/index.d.ts +3 -0
  7. package/dist/components/social_icons.d.ts +6 -0
  8. package/dist/hooks/index.d.ts +7 -0
  9. package/dist/hooks/useAppCheck.d.ts +20 -0
  10. package/dist/hooks/useFirebaseAuthController.d.ts +15 -0
  11. package/dist/hooks/useFirebaseRealTimeDBDelegate.d.ts +5 -0
  12. package/dist/hooks/useFirebaseStorageSource.d.ts +14 -0
  13. package/dist/hooks/useFirestoreDriver.d.ts +56 -0
  14. package/dist/hooks/useInitialiseFirebase.d.ts +34 -0
  15. package/dist/hooks/useRecaptcha.d.ts +8 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.es.js +2757 -0
  18. package/dist/index.es.js.map +1 -0
  19. package/dist/index.umd.js +2743 -0
  20. package/dist/index.umd.js.map +1 -0
  21. package/dist/social_icons.d.ts +6 -0
  22. package/dist/types/appcheck.d.ts +10 -0
  23. package/dist/types/auth.d.ts +41 -0
  24. package/dist/types/index.d.ts +3 -0
  25. package/dist/types/text_search.d.ts +39 -0
  26. package/dist/utils/algolia.d.ts +9 -0
  27. package/dist/utils/collections_firestore.d.ts +5 -0
  28. package/dist/utils/database.d.ts +2 -0
  29. package/dist/utils/index.d.ts +7 -0
  30. package/dist/utils/local_text_search_controller.d.ts +2 -0
  31. package/dist/utils/pinecone.d.ts +24 -0
  32. package/dist/utils/rebase_search_controller.d.ts +73 -0
  33. package/dist/utils/text_search_controller.d.ts +13 -0
  34. package/package.json +61 -0
  35. package/src/components/FirebaseLoginView.tsx +703 -0
  36. package/src/components/RebaseFirebaseApp.tsx +275 -0
  37. package/src/components/RebaseFirebaseAppProps.tsx +180 -0
  38. package/src/components/index.ts +3 -0
  39. package/src/components/social_icons.tsx +135 -0
  40. package/src/hooks/index.ts +7 -0
  41. package/src/hooks/useAppCheck.ts +101 -0
  42. package/src/hooks/useFirebaseAuthController.ts +334 -0
  43. package/src/hooks/useFirebaseRealTimeDBDelegate.ts +269 -0
  44. package/src/hooks/useFirebaseStorageSource.ts +208 -0
  45. package/src/hooks/useFirestoreDriver.ts +778 -0
  46. package/src/hooks/useInitialiseFirebase.ts +132 -0
  47. package/src/hooks/useRecaptcha.tsx +28 -0
  48. package/src/index.ts +4 -0
  49. package/src/social_icons.tsx +135 -0
  50. package/src/types/appcheck.ts +11 -0
  51. package/src/types/auth.tsx +74 -0
  52. package/src/types/index.ts +3 -0
  53. package/src/types/text_search.ts +42 -0
  54. package/src/utils/algolia.ts +27 -0
  55. package/src/utils/collections_firestore.ts +149 -0
  56. package/src/utils/database.ts +39 -0
  57. package/src/utils/index.ts +7 -0
  58. package/src/utils/local_text_search_controller.ts +143 -0
  59. package/src/utils/pinecone.ts +75 -0
  60. package/src/utils/rebase_search_controller.ts +356 -0
  61. package/src/utils/text_search_controller.ts +34 -0
@@ -0,0 +1,275 @@
1
+ import React from "react";
2
+ import { GoogleAuthProvider } from "@firebase/auth";
3
+
4
+ import {
5
+ Rebase,
6
+ ModeControllerProvider,
7
+ SnackbarProvider,
8
+ useBrowserTitleAndIcon,
9
+ useBuildLocalConfigurationPersistence,
10
+ useBuildModeController,
11
+ useBuildAdminModeController,
12
+ AdminModeControllerProvider,
13
+ useValidateAuthenticator,
14
+ RebaseRoutes
15
+ } from "@rebasepro/core";
16
+ import {
17
+ AppBar,
18
+ Drawer,
19
+ Scaffold,
20
+ SideDialogs,
21
+ useBuildCollectionRegistryController,
22
+ useBuildUrlController,
23
+ useBuildNavigationStateController,
24
+ CollectionRegistryContext,
25
+ UrlContext,
26
+ NavigationStateContext
27
+ } from "@rebasepro/cms";
28
+ import { PropertyConfig } from "@rebasepro/types";
29
+ import { CenteredView, CircularProgressCenter } from "@rebasepro/ui";
30
+ import { buildRebaseData } from "@rebasepro/common";
31
+ import { Route, Routes, Outlet } from "react-router-dom";
32
+
33
+ import { RebaseFirebaseAppProps } from "./RebaseFirebaseAppProps";
34
+ import { FirebaseLoginView } from "./FirebaseLoginView";
35
+ import {
36
+ useAppCheck,
37
+ useFirebaseAuthController,
38
+ useFirebaseStorageSource,
39
+ useFirestoreDriver,
40
+ useInitialiseFirebase,
41
+ } from "../hooks";
42
+
43
+ import { FirebaseAuthController } from "../types";
44
+
45
+ const DEFAULT_SIGN_IN_OPTIONS = [
46
+ GoogleAuthProvider.PROVIDER_ID
47
+ ];
48
+
49
+ /**
50
+ * This is the default implementation of a Rebase app using the Firebase services
51
+ * as a backend.
52
+ * You can use this component as a full app, by specifying collections and
53
+ * entity collections.
54
+ *
55
+ * This component is in charge of initialising Firebase, with the given
56
+ * configuration object.
57
+ *
58
+ * If you are building a larger app and need finer control, you can use
59
+ * {@link Rebase}, {@link Scaffold}, {@link SideDialogs}
60
+ * and {@link NavigationRoutes} instead.
61
+ *
62
+ * @param props
63
+
64
+ * @category Firebase
65
+ */
66
+ export function RebaseFirebaseApp({
67
+ name,
68
+ logo,
69
+ logoDark,
70
+ authenticator,
71
+ collections,
72
+ views,
73
+ adminViews,
74
+ textSearchControllerBuilder,
75
+ allowSkipLogin,
76
+ signInOptions = DEFAULT_SIGN_IN_OPTIONS,
77
+ firebaseConfig,
78
+ onFirebaseInit,
79
+ appCheckOptions,
80
+ dateTimeFormat,
81
+ locale,
82
+ basePath,
83
+ baseCollectionPath,
84
+ onAnalyticsEvent,
85
+ propertyConfigs: propertyConfigsProp,
86
+ plugins,
87
+ autoOpenDrawer,
88
+ firestoreIndexesBuilder,
89
+ components,
90
+ localTextSearchEnabled = false,
91
+ userManagement
92
+ }: RebaseFirebaseAppProps) {
93
+
94
+ /**
95
+ * Update the browser title and icon
96
+ */
97
+ useBrowserTitleAndIcon(name, logo);
98
+
99
+ const propertyConfigs: Record<string, PropertyConfig> = (propertyConfigsProp ?? [])
100
+ .map(pc => ({
101
+ [pc.key]: pc
102
+ }))
103
+ .reduce((a, b) => ({ ...a, ...b }), {});
104
+
105
+ const {
106
+ firebaseApp,
107
+ firebaseConfigLoading,
108
+ configError
109
+ } = useInitialiseFirebase({
110
+ onFirebaseInit,
111
+ firebaseConfig
112
+ });
113
+
114
+ /**
115
+ * Controller used to manage the dark or light color mode
116
+ */
117
+ const modeController = useBuildModeController();
118
+ const adminModeController = useBuildAdminModeController();
119
+
120
+ const {
121
+ loading,
122
+ appCheckVerified,
123
+ error
124
+ } = useAppCheck({
125
+ firebaseApp,
126
+ options: appCheckOptions
127
+ });
128
+
129
+ /**
130
+ * Controller for managing authentication
131
+ */
132
+ const authController: FirebaseAuthController = useFirebaseAuthController({
133
+ firebaseApp,
134
+ signInOptions
135
+ });
136
+
137
+ /**
138
+ * Controller for saving some user preferences locally.
139
+ */
140
+ const userConfigPersistence = useBuildLocalConfigurationPersistence();
141
+
142
+ const firestoreDelegate = useFirestoreDriver({
143
+ firebaseApp,
144
+ textSearchControllerBuilder: textSearchControllerBuilder,
145
+ firestoreIndexesBuilder: firestoreIndexesBuilder,
146
+ localTextSearchEnabled
147
+ })
148
+
149
+ /**
150
+ * Controller used for saving and fetching files in storage
151
+ */
152
+ const storageSource = useFirebaseStorageSource({
153
+ firebaseApp
154
+ });
155
+
156
+ /**
157
+ * Validate authenticator
158
+ */
159
+ const {
160
+ authLoading,
161
+ canAccessMainView,
162
+ notAllowedError
163
+ } = useValidateAuthenticator({
164
+ authController,
165
+ authenticator,
166
+ data: buildRebaseData(firestoreDelegate),
167
+ storageSource
168
+ });
169
+
170
+ const collectionRegistryController = useBuildCollectionRegistryController({
171
+ userConfigPersistence
172
+ });
173
+
174
+ const urlController = useBuildUrlController({
175
+ basePath: basePath ?? "/",
176
+ baseCollectionPath: baseCollectionPath ?? "/c",
177
+ collectionRegistryController
178
+ });
179
+
180
+ const navigationStateController = useBuildNavigationStateController({
181
+ collections,
182
+ views,
183
+ adminViews,
184
+ authController,
185
+ data: buildRebaseData(firestoreDelegate),
186
+ plugins,
187
+ collectionRegistryController,
188
+ urlController,
189
+ adminMode: adminModeController.mode,
190
+ userManagement
191
+ });
192
+
193
+ if (firebaseConfigLoading || !firebaseApp || loading) {
194
+ return <>
195
+ <CircularProgressCenter />
196
+ </>;
197
+ }
198
+
199
+ if (configError) {
200
+ return <CenteredView>{configError}</CenteredView>;
201
+ }
202
+
203
+ return (
204
+ <SnackbarProvider>
205
+ <ModeControllerProvider value={modeController}>
206
+ <AdminModeControllerProvider value={adminModeController}>
207
+
208
+ <CollectionRegistryContext.Provider value={collectionRegistryController}>
209
+ <UrlContext.Provider value={urlController}>
210
+ <NavigationStateContext.Provider value={navigationStateController}>
211
+ <Rebase
212
+ authController={authController}
213
+ userConfigPersistence={userConfigPersistence}
214
+ dateTimeFormat={dateTimeFormat}
215
+ driver={firestoreDelegate}
216
+ storageSource={storageSource}
217
+ userManagement={userManagement}
218
+ entityLinkBuilder={({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
219
+ locale={locale}
220
+ onAnalyticsEvent={onAnalyticsEvent}
221
+ plugins={plugins}
222
+ propertyConfigs={propertyConfigs}>
223
+ {({
224
+ context,
225
+ loading
226
+ }) => {
227
+
228
+ let component;
229
+ if (loading || authLoading) {
230
+ component = <CircularProgressCenter size={"large"} />;
231
+ } else {
232
+ const usedLogo = modeController.mode === "dark" && logoDark ? logoDark : logo;
233
+ if (!canAccessMainView) {
234
+ const LoginViewUsed = components?.LoginView ?? FirebaseLoginView;
235
+ component = (
236
+ <LoginViewUsed
237
+ logo={usedLogo}
238
+ allowSkipLogin={allowSkipLogin}
239
+ signInOptions={signInOptions ?? DEFAULT_SIGN_IN_OPTIONS}
240
+ firebaseApp={firebaseApp}
241
+ authController={authController}
242
+ notAllowedError={notAllowedError} />
243
+ );
244
+ } else {
245
+ component = (
246
+ <Routes>
247
+ <Route element={
248
+ <Scaffold
249
+ logo={usedLogo}
250
+ autoOpenDrawer={autoOpenDrawer}>
251
+ <AppBar title={name} logo={usedLogo} />
252
+ <Drawer />
253
+ <Outlet />
254
+ <SideDialogs />
255
+ </Scaffold>
256
+ }>
257
+ {components?.HomePage && <Route path="/" element={<components.HomePage />} />}
258
+ <Route path="/c/*" element={<RebaseRoutes />} />
259
+ </Route>
260
+ </Routes>
261
+ );
262
+ }
263
+ }
264
+
265
+ return component;
266
+ }}
267
+ </Rebase>
268
+ </NavigationStateContext.Provider>
269
+ </UrlContext.Provider>
270
+ </CollectionRegistryContext.Provider>
271
+ </AdminModeControllerProvider>
272
+ </ModeControllerProvider>
273
+ </SnackbarProvider>
274
+ );
275
+ }
@@ -0,0 +1,180 @@
1
+ import React from "react";
2
+
3
+ import { Authenticator, AnalyticsEvent, AppView, AppViewsBuilder, EntityCollection, EntityCollectionsBuilder, RebasePlugin, Locale, PropertyConfig } from "@rebasepro/types";
4
+ import { UserManagementDelegate } from "@rebasepro/types";
5
+ import { FirebaseApp } from "@firebase/app";
6
+ import { FirebaseLoginViewProps } from "./FirebaseLoginView";
7
+ import {
8
+ AppCheckOptions,
9
+ FirebaseSignInOption,
10
+ FirebaseSignInProvider,
11
+ FirebaseUserWrapper,
12
+ FirestoreTextSearchControllerBuilder
13
+ } from "../types";
14
+ import { FirestoreIndexesBuilder } from "../hooks";
15
+
16
+ /**
17
+ * Main entry point that defines the CMS configuration
18
+ * @category Firebase
19
+ */
20
+ export type RebaseFirebaseAppProps = {
21
+
22
+ /**
23
+ * Name of the app, displayed as the main title and in the tab title
24
+ */
25
+ name: string;
26
+
27
+ /**
28
+ * Logo to be displayed in the drawer of the CMS.
29
+ * If not specified, the Rebase logo will be used
30
+ */
31
+ logo?: string;
32
+
33
+ /**
34
+ * Logo used in dark mode. If not specified, `logo` will always be used.
35
+ */
36
+ logoDark?: string;
37
+
38
+ /**
39
+ * List of the mapped collections in the CMS.
40
+ * Each entry relates to a collection in the root database.
41
+ * Each of the navigation entries in this field
42
+ * generates an entry in the main menu.
43
+ */
44
+ collections?: EntityCollection[] | EntityCollectionsBuilder;
45
+
46
+ /**
47
+ * Custom additional views created by the developer, added to the main
48
+ * navigation
49
+ */
50
+ views?: AppView[] | AppViewsBuilder;
51
+
52
+ /**
53
+ * Custom additional views created by the developer, added to the admin
54
+ * navigation
55
+ */
56
+ adminViews?: AppView[] | AppViewsBuilder;
57
+
58
+ /**
59
+ * Record of custom form fields to be used in the CMS.
60
+ * You can use the key to reference the custom field in
61
+ * the `propertyConfig` prop of a property in a collection.
62
+ */
63
+ propertyConfigs?: PropertyConfig[];
64
+
65
+ /**
66
+ * Do the users need to log in to access the CMS.
67
+ * You can specify an Authenticator function to discriminate which users can
68
+ * access the CMS or not.
69
+ * If not specified, authentication is enabled but no user restrictions
70
+ * apply
71
+ */
72
+ authenticator?: boolean | Authenticator<FirebaseUserWrapper>;
73
+
74
+ /**
75
+ * List of sign in options that will be displayed in the login
76
+ * view if `authentication` is enabled. You can pass Firebase providers strings,
77
+ * such as `firebase.auth.GoogleAuthProvider.PROVIDER_ID` or include additional
78
+ * config such as scopes or custom parameters
79
+ * {@link FirebaseSignInOption}
80
+ * Defaults to Google sign in only.
81
+ */
82
+ signInOptions?: Array<FirebaseSignInProvider | FirebaseSignInOption>;
83
+
84
+ /**
85
+ * If authentication is enabled, allow the user to access the content
86
+ * without login.
87
+ */
88
+ allowSkipLogin?: boolean;
89
+
90
+ /**
91
+ * Firebase configuration of the project. If you afe deploying the app to
92
+ * Firebase hosting, you don't need to specify this value
93
+ */
94
+ firebaseConfig?: Record<string, unknown>;
95
+
96
+ /**
97
+ * Optional callback after Firebase has been initialised. Useful for
98
+ * using the local emulator or retrieving the used configuration.
99
+ * @param config
100
+ */
101
+ onFirebaseInit?: (config: object, app: FirebaseApp) => void;
102
+
103
+ /**
104
+ * Use this to enable Firebase App Check
105
+ */
106
+ appCheckOptions?: AppCheckOptions;
107
+
108
+ /**
109
+ * Format of the dates in the CMS.
110
+ * Defaults to 'MMMM dd, yyyy, HH:mm:ss'
111
+ */
112
+ dateTimeFormat?: string;
113
+
114
+ /**
115
+ * Locale of the CMS, currently only affecting dates
116
+ */
117
+ locale?: Locale;
118
+
119
+ /**
120
+ * Use this controller to return text search results as document ids, that
121
+ * get then fetched from Firestore.
122
+ *
123
+ */
124
+ textSearchControllerBuilder?: FirestoreTextSearchControllerBuilder;
125
+
126
+ /**
127
+ * Default path under the navigation routes of the CMS will be created
128
+ */
129
+ basePath?: string;
130
+
131
+ /**
132
+ * Default path under the collection routes of the CMS will be created
133
+ */
134
+ baseCollectionPath?: string;
135
+
136
+ /**
137
+ * Callback used to get analytics events from the CMS
138
+ */
139
+ onAnalyticsEvent?: (event: AnalyticsEvent, data?: object) => void;
140
+
141
+ /**
142
+ * Use plugins to modify the behaviour of the CMS.
143
+ * Currently, in ALPHA, and likely subject to change.
144
+ */
145
+ plugins?: RebasePlugin[];
146
+
147
+ /**
148
+ * Open the drawer on hover. Defaults to `false`
149
+ */
150
+ autoOpenDrawer?: boolean;
151
+
152
+ /**
153
+ * Use this builder to indicate which indexes are available in your
154
+ * Firestore database. This is used to allow filtering and sorting
155
+ * for multiple fields in the CMS.
156
+ */
157
+ firestoreIndexesBuilder?: FirestoreIndexesBuilder;
158
+
159
+ localTextSearchEnabled?: boolean;
160
+
161
+ components?: ComponentsRegistry;
162
+
163
+ /**
164
+ * Delegate for user and role management. Provides the admin views if specified.
165
+ */
166
+ userManagement?: UserManagementDelegate;
167
+
168
+ };
169
+
170
+ export type ComponentsRegistry = {
171
+ /**
172
+ * Component to be used to render the login view
173
+ */
174
+ LoginView?: React.ComponentType<FirebaseLoginViewProps>;
175
+
176
+ /**
177
+ * Component to be used to render the home page
178
+ */
179
+ HomePage?: React.ComponentType;
180
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./RebaseFirebaseApp";
2
+ export * from "./RebaseFirebaseAppProps";
3
+ export * from "./FirebaseLoginView";
@@ -0,0 +1,135 @@
1
+ export const googleIcon = (mode: "light" | "dark") => <>
2
+ <svg
3
+ xmlns="http://www.w3.org/2000/svg"
4
+ viewBox="0 0 64 64"
5
+ width={32}
6
+ height={32}
7
+ >
8
+ <linearGradient
9
+ id="95yY7w43Oj6n2vH63j6HJb"
10
+ x1="29.401"
11
+ x2="29.401"
12
+ y1="4.064"
13
+ y2="106.734"
14
+ gradientTransform="matrix(1 0 0 -1 0 66)"
15
+ gradientUnits="userSpaceOnUse"
16
+ >
17
+ <stop offset="0" stopColor="#ff5840"/>
18
+ <stop offset=".007" stopColor="#ff5840"/>
19
+ <stop offset=".989" stopColor="#fa528c"/>
20
+ <stop offset="1" stopColor="#fa528c"/>
21
+ </linearGradient>
22
+ <path
23
+ fill="url(#95yY7w43Oj6n2vH63j6HJb)"
24
+ d="M47.46,15.5l-1.37,1.48c-1.34,1.44-3.5,1.67-5.15,0.6c-2.71-1.75-6.43-3.13-11-2.37 c-4.94,0.83-9.17,3.85-11.64, 7.97l-8.03-6.08C14.99,9.82,23.2,5,32.5,5c5,0,9.94,1.56,14.27,4.46 C48.81,10.83,49.13,13.71,47.46,15.5z"
25
+ />
26
+ <linearGradient
27
+ id="95yY7w43Oj6n2vH63j6HJc"
28
+ x1="12.148"
29
+ x2="12.148"
30
+ y1=".872"
31
+ y2="47.812"
32
+ gradientTransform="matrix(1 0 0 -1 0 66)"
33
+ gradientUnits="userSpaceOnUse"
34
+ >
35
+ <stop offset="0" stopColor="#feaa53"/>
36
+ <stop offset=".612" stopColor="#ffcd49"/>
37
+ <stop offset="1" stopColor="#ffde44"/>
38
+ </linearGradient>
39
+ <path
40
+ fill="url(#95yY7w43Oj6n2vH63j6HJc)"
41
+ d="M16.01,30.91c-0.09,2.47,0.37,4.83,1.27,6.96l-8.21,6.05c-1.35-2.51-2.3-5.28-2.75-8.22 c-1.06-6.88,0.54-13.38, 3.95-18.6l8.03,6.08C16.93,25.47,16.1,28.11,16.01,30.91z"
42
+ />
43
+ <linearGradient
44
+ id="95yY7w43Oj6n2vH63j6HJd"
45
+ x1="29.76"
46
+ x2="29.76"
47
+ y1="32.149"
48
+ y2="-6.939"
49
+ gradientTransform="matrix(1 0 0 -1 0 66)"
50
+ gradientUnits="userSpaceOnUse"
51
+ >
52
+ <stop offset="0" stopColor="#42d778"/>
53
+ <stop offset=".428" stopColor="#3dca76"/>
54
+ <stop offset="1" stopColor="#34b171"/>
55
+ </linearGradient>
56
+ <path
57
+ fill="url(#95yY7w43Oj6n2vH63j6HJd)"
58
+ d="M50.45,51.28c-4.55,4.07-10.61,6.57-17.36,6.71C22.91,58.2,13.66,52.53,9.07,43.92l8.21-6.05 C19.78,43.81, 25.67,48,32.5,48c3.94,0,7.52-1.28,10.33-3.44L50.45,51.28z"
59
+ />
60
+ <linearGradient
61
+ id="95yY7w43Oj6n2vH63j6HJe"
62
+ x1="46"
63
+ x2="46"
64
+ y1="3.638"
65
+ y2="35.593"
66
+ gradientTransform="matrix(1 0 0 -1 0 66)"
67
+ gradientUnits="userSpaceOnUse"
68
+ >
69
+ <stop offset="0" stopColor="#155cde"/>
70
+ <stop offset=".278" stopColor="#1f7fe5"/>
71
+ <stop offset=".569" stopColor="#279ceb"/>
72
+ <stop offset=".82" stopColor="#2cafef"/>
73
+ <stop offset="1" stopColor="#2eb5f0"/>
74
+ </linearGradient>
75
+ <path
76
+ fill="url(#95yY7w43Oj6n2vH63j6HJe)"
77
+ d="M59,31.97c0.01,7.73-3.26,14.58-8.55,19.31l-7.62-6.72c2.1-1.61,3.77-3.71,4.84-6.15
78
+ c0.29-0.66-0.2-1.41-0.92-1.41H37c-2.21,0-4-1.79-4-4v-2c0-2.21,1.79-4,4-4h17C56.75,27,59,29.22,59,31.97z"
79
+ />
80
+ </svg>
81
+ </>;
82
+
83
+ export const appleIcon = (mode: "light" | "dark") => <svg width={32} height={32}
84
+ viewBox="0 0 56 56"
85
+ style={{ transform: "scale(2.8)" }}
86
+ version="1.1"
87
+ xmlns="http://www.w3.org/2000/svg">
88
+ <g stroke={mode === "light" ? "#424245" : "white"} strokeWidth="0.5"
89
+ fillRule="evenodd">
90
+ <path
91
+ d="M28.2226562,20.3846154 C29.0546875,20.3846154 30.0976562,19.8048315 30.71875,19.0317864 C31.28125,18.3312142 31.6914062,17.352829 31.6914062,16.3744437 C31.6914062,16.2415766 31.6796875,16.1087095 31.65625,16 C30.7304687,16.0362365 29.6171875,16.640178 28.9492187,17.4494596 C28.421875,18.06548 27.9414062,19.0317864 27.9414062,20.0222505 C27.9414062,20.1671964 27.9648438,20.3121424 27.9765625,20.3604577 C28.0351562,20.3725366 28.1289062,20.3846154 28.2226562,20.3846154 Z M25.2929688,35 C26.4296875,35 26.9335938,34.214876 28.3515625,34.214876 C29.7929688,34.214876 30.109375,34.9758423 31.375,34.9758423 C32.6171875,34.9758423 33.4492188,33.792117 34.234375,32.6325493 C35.1132812,31.3038779 35.4765625,29.9993643 35.5,29.9389701 C35.4179688,29.9148125 33.0390625,28.9122695 33.0390625,26.0979021 C33.0390625,23.6579784 34.9140625,22.5588048 35.0195312,22.474253 C33.7773438,20.6382708 31.890625,20.5899555 31.375,20.5899555 C29.9804688,20.5899555 28.84375,21.4596313 28.1289062,21.4596313 C27.3554688,21.4596313 26.3359375,20.6382708 25.1289062,20.6382708 C22.8320312,20.6382708 20.5,22.5950413 20.5,26.2911634 C20.5,28.5861411 21.3671875,31.013986 22.4335938,32.5842339 C23.3476562,33.9129053 24.1445312,35 25.2929688,35 Z"
92
+ fill={mode === "light" ? "#424245" : "white"} fillRule="nonzero"/>
93
+ </g>
94
+ </svg>;
95
+
96
+ export const githubIcon = (mode: "light" | "dark") => <svg
97
+ fill={mode === "light" ? "#1c1e21" : "white"}
98
+ role="img"
99
+ viewBox="0 0 24 24"
100
+ width={28}
101
+ height={28}
102
+ xmlns="http://www.w3.org/2000/svg">
103
+ <path
104
+ d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
105
+ </svg>;
106
+
107
+
108
+ export const facebookIcon = (mode: "light" | "dark") => <svg
109
+ xmlns="http://www.w3.org/2000/svg"
110
+ width={28} height={28}
111
+ viewBox="0 0 90 90">
112
+ <g>
113
+ <path
114
+ d="M90,15.001C90,7.119,82.884,0,75,0H15C7.116,0,0,7.119,0,15.001v59.998 C0,82.881,7.116,90,15.001,90H45V56H34V41h11v-5.844C45,25.077,52.568,16,61.875,16H74v15H61.875C60.548,31,59,32.611,59,35.024V41 h15v15H59v34h16c7.884,0,15-7.119,15-15.001V15.001z"
115
+ fill={mode === "light" ? "#39569c" : "white"}/>
116
+ </g>
117
+ </svg>;
118
+
119
+ export const microsoftIcon = (mode: "light" | "dark") => <svg
120
+ xmlns="http://www.w3.org/2000/svg" width={28} height={28}
121
+ viewBox="0 0 480 480">
122
+ <g>
123
+ <path
124
+ d="M0.176,224L0.001,67.963l192-26.072V224H0.176z M224.001,37.241L479.937,0v224H224.001V37.241z M479.999,256l-0.062,224 l-255.936-36.008V256H479.999z M192.001,439.918L0.157,413.621L0.147,256h191.854V439.918z"
125
+ fill={mode === "light" ? "#00a2ed" : "white"}/>
126
+ </g>
127
+ </svg>;
128
+
129
+ export const twitterIcon = (mode: "light" | "dark") => <svg
130
+ xmlns="http://www.w3.org/2000/svg" width={28} height={28}
131
+ viewBox="0 0 24 24">
132
+ <path fill={mode === "light" ? "#00acee" : "white"}
133
+ d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
134
+ </svg>;
135
+
@@ -0,0 +1,7 @@
1
+ export * from "./useFirebaseAuthController";
2
+ export * from "./useFirebaseStorageSource";
3
+ export * from "./useInitialiseFirebase";
4
+ export * from "./useAppCheck";
5
+ export * from "./useFirestoreDriver";
6
+ export * from "./useFirebaseRealTimeDBDelegate";
7
+ export * from "./useRecaptcha";