@bagelink/vue 0.0.25 → 0.0.32

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 (82) hide show
  1. package/package.json +32 -9
  2. package/src/components/Btn.vue +221 -0
  3. package/src/components/Comments.vue +265 -0
  4. package/src/components/ContactArray.vue +127 -0
  5. package/src/components/ContactSubmissions.vue +42 -0
  6. package/src/components/DataPreview.vue +72 -0
  7. package/src/components/DropDown.vue +122 -0
  8. package/src/components/FileUploader.vue +344 -0
  9. package/src/components/FormKitTable.vue +250 -0
  10. package/src/components/FormSchema.vue +65 -0
  11. package/src/components/LangText.vue +30 -0
  12. package/src/components/ListItem.vue +16 -0
  13. package/src/components/ListView.vue +39 -0
  14. package/src/components/MaterialIcon.vue +16 -0
  15. package/src/components/Modal.vue +50 -0
  16. package/src/components/ModalForm.vue +94 -0
  17. package/src/components/NavBar.vue +343 -0
  18. package/src/components/PageTitle.vue +17 -0
  19. package/src/components/PersonPreview.vue +205 -0
  20. package/src/components/PersonPreviewFormkit.vue +205 -0
  21. package/src/components/RTXEditor.vue +147 -0
  22. package/src/components/RouterWrapper.vue +9 -0
  23. package/src/components/TabbedLayout.vue +80 -0
  24. package/src/components/TableSchema.vue +213 -0
  25. package/src/components/TopBar.vue +5 -0
  26. package/src/components/charts/BarChart.vue +290 -0
  27. package/src/components/dashboard/Lineart.vue +165 -0
  28. package/src/components/form/ItemRef.vue +38 -0
  29. package/src/components/form/MaterialIcon.vue +19 -0
  30. package/src/components/form/PlainInputField.vue +80 -0
  31. package/src/components/form/inputs/CheckInput.vue +143 -0
  32. package/src/components/form/inputs/Checkbox.vue +69 -0
  33. package/src/components/form/inputs/ColorPicker.vue +37 -0
  34. package/src/components/form/inputs/CurrencyInput.vue +133 -0
  35. package/src/components/form/inputs/DateInput.vue +49 -0
  36. package/src/components/form/inputs/DatetimeInput.vue +46 -0
  37. package/src/components/form/inputs/DurationInput.vue +51 -0
  38. package/src/components/form/inputs/DynamicLinkField.vue +140 -0
  39. package/src/components/form/inputs/EmailInput.vue +53 -0
  40. package/src/components/form/inputs/FloatInput.vue +48 -0
  41. package/src/components/form/inputs/IntInput.vue +49 -0
  42. package/src/components/form/inputs/JSONInput.vue +51 -0
  43. package/src/components/form/inputs/LinkField.vue +293 -0
  44. package/src/components/form/inputs/Password.vue +89 -0
  45. package/src/components/form/inputs/PasswordInput.vue +89 -0
  46. package/src/components/form/inputs/PlainText.vue +52 -0
  47. package/src/components/form/inputs/ReadOnlyInput.vue +24 -0
  48. package/src/components/form/inputs/RichTextEditor.vue +54 -0
  49. package/src/components/form/inputs/SelectField.vue +253 -0
  50. package/src/components/form/inputs/TableField.vue +321 -0
  51. package/src/components/form/inputs/TextArea.vue +70 -0
  52. package/src/components/form/inputs/TextInput.vue +53 -0
  53. package/src/components/form/inputs/index.ts +17 -0
  54. package/src/components/formkit/AddressArray.vue +240 -0
  55. package/src/components/formkit/BankDetailsArray.vue +265 -0
  56. package/src/components/formkit/ContactArrayFormKit.vue +151 -0
  57. package/src/components/formkit/FileUploader.vue +391 -0
  58. package/src/components/formkit/MiscFields.vue +69 -0
  59. package/src/components/formkit/Toggle.vue +160 -0
  60. package/src/components/formkit/index.ts +29 -0
  61. package/src/components/index.ts +20 -0
  62. package/src/components/whatsapp/form/MsgTemplate.vue +220 -0
  63. package/src/components/whatsapp/form/TextVariableExamples.vue +74 -0
  64. package/src/components/whatsapp/interfaces.ts +58 -0
  65. package/src/index.ts +1 -26
  66. package/src/plugins/bagel.ts +26 -0
  67. package/src/styles/modal.css +90 -0
  68. package/src/types/BagelField.ts +57 -0
  69. package/src/types/BtnOptions.ts +14 -0
  70. package/src/types/Person.ts +51 -0
  71. package/src/types/file.ts +12 -0
  72. package/src/types/index.ts +4 -0
  73. package/src/types/materialIcons.d.ts +3005 -0
  74. package/src/utils/index.ts +57 -0
  75. package/src/utils/modal.ts +95 -0
  76. package/src/utils/objects.ts +81 -0
  77. package/src/utils/strings.ts +29 -0
  78. package/dist/index.cjs +0 -23
  79. package/dist/index.d.cts +0 -12
  80. package/dist/index.d.mts +0 -12
  81. package/dist/index.d.ts +0 -12
  82. package/dist/index.mjs +0 -19
@@ -0,0 +1,160 @@
1
+ <template>
2
+ <div
3
+ class="bagel-input checkbox"
4
+ :class="{ check: context?.attrs.isCheckbox }"
5
+ :title="context?.help"
6
+ >
7
+ <label class="switch">
8
+ <input
9
+ @change="() => props.context?.node.input(inputVal)"
10
+ type="checkbox"
11
+ v-model="inputVal"
12
+ :id="context?.id"
13
+ >
14
+ <span class="slider round" />
15
+ </label>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { watch } from 'vue';
21
+
22
+ const props = defineProps({
23
+ context: Object,
24
+ });
25
+
26
+ let inputVal = $ref(false);
27
+
28
+ watch(
29
+ () => props.context?.value,
30
+ (newVal) => {
31
+ inputVal = newVal;
32
+ },
33
+ { immediate: true },
34
+ );
35
+ </script>
36
+
37
+ <style>
38
+ .checkbox-label {
39
+ display: flex;
40
+ gap: 0.5rem;
41
+ flex-direction: row-reverse;
42
+ justify-content: flex-end;
43
+ align-items: center;
44
+ cursor: pointer;
45
+ }
46
+ </style>
47
+
48
+ <style scoped>
49
+ .no-edit {
50
+ pointer-events: none;
51
+ }
52
+
53
+ .radio-wrap p {
54
+ display: inline-block;
55
+ color: var(--input-bg);
56
+ font-size: var(--input-font-size);
57
+ margin-inline-end: 10px;
58
+ }
59
+
60
+ .radio-wrap label {
61
+ padding: 3px 5px;
62
+ display: inline-block;
63
+ border-radius: var(--input-border-radius);
64
+ font-size: var(--input-font-size);
65
+ background: var(--input-bg);
66
+ color: var(--bgl-black);
67
+ text-align: center;
68
+ margin: 8px 5px;
69
+ cursor: pointer;
70
+ user-select: none;
71
+ }
72
+
73
+ .bagel-input .radio-wrap label::after {
74
+ background: transparent;
75
+ }
76
+
77
+ .radio-wrap input {
78
+ display: none;
79
+ }
80
+
81
+ .radio-wrap input:checked:checked + label {
82
+ background: var(--bgl-blue);
83
+ color: var(--bgl-white);
84
+ }
85
+
86
+ .checkbox {
87
+ position: relative;
88
+ }
89
+
90
+ .switch {
91
+ position: relative;
92
+ display: inline-block;
93
+ height: calc(var(--input-height) / 2);
94
+ width: var(--input-height);
95
+ border-radius: var(--input-height);
96
+ }
97
+
98
+ .switch input {
99
+ opacity: 0;
100
+ width: 0;
101
+ height: 0;
102
+ }
103
+ .bagel-input.checkbox.check {
104
+ margin: 0;
105
+ }
106
+ .bagel-input.checkbox.check .switch {
107
+ width: calc(var(--input-height) / 2);
108
+ height: calc(var(--input-height) / 2);
109
+ transition: 0.2s;
110
+ }
111
+ .bagel-input.checkbox.check .slider:before {
112
+ position: absolute;
113
+ font-family: 'Material Symbols Outlined', serif;
114
+ content: '';
115
+ color: var(--bgl-white);
116
+ background: transparent;
117
+ display: flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ }
121
+ .bagel-input.checkbox.check input:checked + .slider:before {
122
+ transform: none;
123
+ content: 'check';
124
+ }
125
+
126
+ .slider {
127
+ position: absolute;
128
+ cursor: pointer;
129
+ top: 0;
130
+ left: 0;
131
+ right: 0;
132
+ bottom: 0;
133
+ background: var(--input-bg);
134
+ -webkit-transition: 0.4s;
135
+ transition: 0.4s;
136
+ border-radius: calc(var(--input-height) / 2);
137
+ box-shadow: inset 0 0 10px #00000020;
138
+ }
139
+
140
+ .slider:before {
141
+ position: absolute;
142
+ content: '';
143
+ height: calc(var(--input-height) / 2 - 4px);
144
+ width: calc(var(--input-height) / 2 - 4px);
145
+ left: 2px;
146
+ bottom: 2px;
147
+ border-radius: 50%;
148
+ background: var(--bgl-white);
149
+ -webkit-transition: 0.4s;
150
+ transition: 0.4s;
151
+ }
152
+
153
+ input:checked + .slider {
154
+ background: var(--bgl-blue);
155
+ }
156
+
157
+ input:checked + .slider:before {
158
+ transform: translateX(calc(var(--input-height) / 2));
159
+ }
160
+ </style>
@@ -0,0 +1,29 @@
1
+ import { createInput } from '@formkit/vue';
2
+ import ContactArrayFormKit from '@/components/formkit/ContactArrayFormKit.vue';
3
+ import AddressArray from './AddressArray.vue';
4
+ import BankDetailsArray from './BankDetailsArray.vue';
5
+ import MiscFieldsBtns from './MiscFields.vue';
6
+ import Toggle from './Toggle.vue';
7
+ import FileUploader from './FileUploader.vue';
8
+ import TextVariableExamples from '@/components/whatsapp/form/TextVariableExamples.vue';
9
+ import PPV from '../PersonPreviewFormkit.vue';
10
+
11
+ const ContactArray = createInput(ContactArrayFormKit);
12
+ const Address = createInput(AddressArray);
13
+ const BankDetails = createInput(BankDetailsArray);
14
+ const MiscFields = createInput(MiscFieldsBtns);
15
+ const ToggleSwitch = createInput(Toggle);
16
+ const FileUpload = createInput(FileUploader);
17
+ const TextVariables = createInput(TextVariableExamples);
18
+ const PersonPreview = createInput(PPV);
19
+
20
+ export {
21
+ TextVariables,
22
+ ContactArray,
23
+ PersonPreview,
24
+ Address,
25
+ BankDetails,
26
+ MiscFields,
27
+ ToggleSwitch,
28
+ FileUpload,
29
+ };
@@ -0,0 +1,20 @@
1
+ export * as RTXEditor from './RTXEditor.vue';
2
+ export * as MaterialIcon from './MaterialIcon.vue';
3
+ export * as BagelForm from './BagelForm.vue';
4
+ export * as NavBar from './NavBar.vue';
5
+ export * as Btn from './Btn.vue';
6
+ export * as Modal from './Modal.vue';
7
+ export * as BarChart from './charts/BarChart.vue';
8
+ export * as DropDown from './DropDown.vue';
9
+ export * as ListView from './ListView.vue';
10
+ export * as ListItem from './ListItem.vue';
11
+ export * as TabbedLayout from './TabbedLayout.vue';
12
+ export * as Comments from './Comments.vue';
13
+ export * as PageTitle from './PageTitle.vue';
14
+ export * as ModalForm from './ModalForm.vue';
15
+ export * as TextInput from './form/inputs/TextInput.vue';
16
+ export * as DataPreview from './DataPreview.vue';
17
+ export * as SubscriptionCharges from './SubscriptionCharges.vue';
18
+ export * as FormSchema from './FormSchema.vue';
19
+ export * as TableSchema from './TableSchema.vue';
20
+ export * as TopBar from './TopBar.vue';
@@ -0,0 +1,220 @@
1
+ <template>
2
+ <div class="main-content">
3
+ <PageTitle>Whatsapp Template</PageTitle>
4
+ <div class="view-wrapper card thin">
5
+ <div class="whatsapp-wrap">
6
+ <div class="create-template-form">
7
+ <FormSchema :schema="whatsappTemplateSchema()" v-model="localWhatsappData" @submit="upsertTemplate" />
8
+ </div>
9
+ <div class="whatsapp-preview" :class="{ whatsappHebrew: localWhatsappData?.language === 'he' }">
10
+ Preview
11
+ <div class="whatsapp-msg">
12
+ <b>{{
13
+ localWhatsappData?.headerText?.replace(regex, replaceHeader)
14
+ }}</b>
15
+ <p class="whatsapp-body">
16
+ {{ localWhatsappData?.bodyText?.replace(regex, replaceBody) }}
17
+ </p>
18
+ <p class="whatsapp-footer">
19
+ {{ localWhatsappData?.footerText }}
20
+ </p>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { onMounted } from 'vue';
30
+ import { PageTitle, FormSchema } from '@/components';
31
+
32
+ import {
33
+ BodyComponent,
34
+ HeaderComponent,
35
+ LocalTemplateData,
36
+ ServerTemplateData,
37
+ FooterComponent,
38
+ } from '../interfaces';
39
+ import { useBagel } from 'src/plugins/bagel';
40
+ import type { FormKitSchemaDefinition } from '@formkit/core';
41
+ import type { RouteLocationNormalizedLoaded, Router } from 'vue-router';
42
+
43
+ const props = defineProps<{
44
+ whatsappTemplateSchema: () => FormKitSchemaDefinition;
45
+ router: Router;
46
+ route: RouteLocationNormalizedLoaded;
47
+ }>()
48
+
49
+ const bagel = useBagel();
50
+
51
+ const regex = /\{\{(\d+)}}/g;
52
+ let localWhatsappData = $ref<LocalTemplateData>();
53
+
54
+ const serverToLocal = (data: ServerTemplateData): LocalTemplateData => ({
55
+ id: data.id,
56
+ status: data.status,
57
+ name: data.name,
58
+ language: data.language,
59
+ headerText: data.components.find(
60
+ (c): c is HeaderComponent => c.type === 'HEADER',
61
+ )?.text,
62
+ bodyText: data.components.find((c): c is BodyComponent => c.type === 'BODY')
63
+ ?.text,
64
+ bodyExamples: data.components.find(
65
+ (c): c is BodyComponent => c.type === 'BODY',
66
+ )?.example?.body_text[0],
67
+ footerText: data.components.find(
68
+ (c): c is FooterComponent => c.type === 'FOOTER',
69
+ )?.text,
70
+ category: data.category,
71
+ });
72
+
73
+ const localToServer = (data: LocalTemplateData) => {
74
+ const obj: any = {};
75
+ obj.language = data.language;
76
+ if (data.id) obj.id = data.id;
77
+ obj.name = data.name;
78
+ obj.components = [];
79
+ obj.category = data.category;
80
+ if (data.headerText) {
81
+ obj.components.push({
82
+ type: 'HEADER',
83
+ format: 'TEXT',
84
+ text: data.headerText,
85
+ });
86
+ }
87
+ if (data.bodyText) {
88
+ const bodyComponent: BodyComponent = { type: 'BODY', text: data.bodyText };
89
+ if (data.bodyExamples) { bodyComponent.example = { body_text: [data.bodyExamples] }; }
90
+ obj.components.push(bodyComponent);
91
+ }
92
+ if (data.footerText) { obj.components.push({ type: 'FOOTER', text: data.footerText }); }
93
+ return obj;
94
+ };
95
+
96
+ const loadTemplateData = async () => {
97
+ const template_name = props.route.params.id;
98
+ if (template_name) {
99
+ const res = await bagel.get(
100
+ `communication/whatsapp/get_template_by_name/${template_name}`,
101
+ );
102
+ localWhatsappData = serverToLocal(res.data[0]);
103
+ }
104
+ };
105
+
106
+ const replaceHeader = (match: any) => {
107
+ const index = +match[2];
108
+ const example = localWhatsappData?.headerExamples?.[index - 1];
109
+ return example || match;
110
+ };
111
+
112
+ const replaceBody = (match: any) => {
113
+ const index = +match[2];
114
+ const example = localWhatsappData?.bodyExamples?.[index - 1];
115
+ return example || match;
116
+ };
117
+
118
+ const upsertTemplate = async () => {
119
+ if (!localWhatsappData) return;
120
+ const payload = localToServer(localWhatsappData);
121
+ console.log(payload);
122
+ if (payload.id) {
123
+ await bagel.put(
124
+ `communication/whatsapp/update_template/${payload.id}`,
125
+ payload,
126
+ );
127
+ } else {
128
+ await bagel.post('communication/whatsapp/create_template', payload);
129
+ props.router.push(`/whatsapp/template/${payload.name}`);
130
+ }
131
+ };
132
+
133
+ onMounted(loadTemplateData);
134
+ </script>
135
+
136
+ <style scoped>
137
+ .btn-end {
138
+ text-align: end;
139
+ }
140
+
141
+ .whatsapp-preview {
142
+ direction: ltr;
143
+ width: 400px;
144
+ padding: 1rem;
145
+ height: auto;
146
+ margin-top: 1rem;
147
+ /* border-left: 1px solid var(--border-color); */
148
+ margin-left: 20px;
149
+ position: sticky;
150
+ top: 15px;
151
+ flex: 1 1 40%;
152
+ }
153
+
154
+ .whatsapp-wrap {
155
+ display: flex;
156
+ gap: 1rem;
157
+ max-width: 1200px;
158
+ overflow: auto;
159
+ height: 100%;
160
+ }
161
+
162
+ .create-template-form {
163
+ flex: 1 0 50%;
164
+ min-width: 300px;
165
+ }
166
+
167
+ .whatsapp-msg {
168
+ background: var(--whatsapp-green);
169
+ border-radius: 0.5rem;
170
+ border-start-start-radius: 0px;
171
+ padding: 10px;
172
+ line-height: 1.5;
173
+ margin-top: 1rem;
174
+ filter: drop-shadow(0 0px 2px var(--bgl-shadow));
175
+ position: relative;
176
+ min-height: 30px;
177
+ }
178
+
179
+ .whatsapp-msg::after {
180
+ content: '';
181
+ inset-inline-start: -5px;
182
+ border-radius: 0.1rem;
183
+ transform: skew(45deg);
184
+ top: 0;
185
+ height: 8px;
186
+ width: 8px;
187
+ background: var(--whatsapp-green);
188
+ position: absolute;
189
+ }
190
+
191
+ .whatsapp-body {
192
+ margin: 2px 0;
193
+ }
194
+
195
+ .whatsapp-footer {
196
+ margin: 0;
197
+ opacity: 0.6;
198
+ font-size: 0.8rem;
199
+ }
200
+
201
+ .whatsappHebrew {
202
+ direction: rtl;
203
+ }
204
+
205
+ .whatsappHebrew .whatsapp-msg::after {
206
+ transform: skew(-45deg);
207
+ }
208
+
209
+ @media screen and (max-width: 1200px) {
210
+ .whatsapp-preview {
211
+ width: 300px;
212
+ }
213
+ }
214
+
215
+ @media screen and (max-width: 910px) {
216
+ .whatsapp-preview {
217
+ display: none;
218
+ }
219
+ }
220
+ </style>
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <div ref="exampleEl">
3
+ <TextInput v-for="v in variables" :key="v" :placeholder="`Variable ${v}`" :modelValue="val?.[v - 1]"
4
+ @update:modelValue="($event: string) => handleUpdate($event, v)" />
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import { onMounted, watch } from 'vue';
10
+ import { FormKitNode } from '@formkit/core';
11
+ import { TextInput } from '@/components';
12
+
13
+ const props = defineProps({
14
+ context: Object,
15
+ });
16
+
17
+ const exampleEl = $ref<HTMLElement>();
18
+ let boundValue = $ref<any>();
19
+ let boundNode = $ref<FormKitNode>();
20
+ let val = $ref<any[]>([]);
21
+
22
+ const handleUpdate = (value: string, index: number) => {
23
+ if (!boundValue) return;
24
+ if (index > val?.length) val = [...val, ...Array(index - val.length).fill(''), value];
25
+ else val?.splice(index - 1, 1, value);
26
+ props.context?.node.input(val);
27
+ };
28
+
29
+ const extractVariables = (text: string): number[] => {
30
+ const matches = text?.match(/{{(\d+)}}/g) || [];
31
+ return matches.map((match: any) => +match.match(/\d+/)[0]);
32
+ };
33
+
34
+ const txtType = $computed(() => (props.context?.id === 'bodyExamples' ? 'bodyText' : 'headerText'));
35
+
36
+ const variables = $computed(() => {
37
+ let vars = extractVariables(boundValue);
38
+ if (txtType === 'headerText') vars.slice(0, 1);
39
+ const nonSequentialDigits = vars?.reduce((acc: number[], currDigit: number, i: number) => {
40
+ const prevDigit = i > 0 ? vars[i - 1] : 0;
41
+ if (currDigit - prevDigit !== 1) {
42
+ acc.push(currDigit);
43
+ }
44
+ return acc;
45
+ }, []);
46
+
47
+ if (nonSequentialDigits?.length) {
48
+ const regex = new RegExp(nonSequentialDigits.map((d: number) => `\\{\\{${d}\\}\\}`).join('|'), 'g');
49
+ const newVal = `${boundValue}`.replace(regex, '');
50
+ boundNode?.input(newVal);
51
+ vars = extractVariables(boundValue);
52
+ }
53
+ const parentEl = exampleEl?.closest('.formkit-outer');
54
+ if (!vars.length && parentEl) {
55
+ parentEl.classList.add('hide');
56
+ } else if (parentEl) {
57
+ parentEl.classList.remove('hide');
58
+ }
59
+ return vars;
60
+ });
61
+
62
+ const setupListners = (node?: FormKitNode) => {
63
+ node?.on('input', (v: any) => {
64
+ boundValue = v.payload;
65
+ });
66
+ };
67
+
68
+ onMounted(() => {
69
+ boundNode = props.context?.node.parent.children.find((c: any) => c.name === txtType);
70
+ setupListners(boundNode);
71
+ });
72
+
73
+ watch(() => props.context?.value, (v: any) => val = v, { immediate: true });
74
+ </script>
@@ -0,0 +1,58 @@
1
+ export interface HeaderComponent {
2
+ type: 'HEADER';
3
+ text: string;
4
+ example_header?: string[];
5
+ }
6
+
7
+ interface Example {
8
+ body_text: string[][];
9
+ }
10
+
11
+ export interface BodyComponent {
12
+ type: 'BODY';
13
+ text: string;
14
+ example?: Example
15
+ add_security_recommendation?: boolean;
16
+ }
17
+
18
+ export interface FooterComponent {
19
+ type: 'FOOTER';
20
+ text: string;
21
+ code_expiration_minutes?: number;
22
+ }
23
+
24
+ interface Button {
25
+ type: 'OTP' | 'CATALOG' | 'MPM' | 'QUICK_REPLY' | 'PHONE_NUMBER' | 'URL';
26
+ text: string;
27
+ // Additional properties specific to each button type
28
+ // Add them here based on the possible button types
29
+ }
30
+
31
+ interface ButtonsComponent {
32
+ type: 'BUTTONS';
33
+ buttons: Button[];
34
+ }
35
+
36
+ export type Component = BodyComponent | FooterComponent | HeaderComponent | ButtonsComponent
37
+
38
+ export interface ServerTemplateData {
39
+ id: string;
40
+ name: string;
41
+ status: string;
42
+ language: string;
43
+ category: string;
44
+ components: readonly Component[];
45
+ }
46
+
47
+ export interface LocalTemplateData {
48
+ id: string;
49
+ name: string;
50
+ language: string;
51
+ status: string;
52
+ category: string;
53
+ headerText?: string;
54
+ headerExamples?: string[];
55
+ bodyText?: string;
56
+ bodyExamples?: string[];
57
+ footerText?: string;
58
+ }
package/src/index.ts CHANGED
@@ -1,26 +1 @@
1
- import { inject } from 'vue';
2
- import type { InjectionKey, Plugin } from 'vue';
3
- import { Bagel } from '@bagelink/sdk';
4
-
5
- export const bagelInjectionKey = Symbol('bagel') as InjectionKey<Bagel>;
6
-
7
- export function useBagel() {
8
- const bagel = inject(bagelInjectionKey);
9
- if (!bagel)
10
- throw new Error('No bagel provided');
11
-
12
- return bagel;
13
- }
14
-
15
- export interface BagelOptions {
16
- host: string
17
- onError?: (err: Error) => void
18
- }
19
-
20
- export const BagelVue: Plugin = {
21
- install: (app, options: BagelOptions) => {
22
- const bagel = new Bagel({ host: options.host, onError: options.onError });
23
- app.config.globalProperties.$bagel = bagel;
24
- app.provide(bagelInjectionKey, bagel);
25
- },
26
- };
1
+ export { BagelVue } from './plugins/bagel';
@@ -0,0 +1,26 @@
1
+ import { inject } from 'vue';
2
+ import type { InjectionKey, Plugin } from 'vue';
3
+ import { Bagel } from '@bagelink/sdk';
4
+
5
+ export const bagelInjectionKey = Symbol('bagel') as InjectionKey<Bagel>;
6
+
7
+ export function useBagel() {
8
+ const bagel = inject(bagelInjectionKey);
9
+ if (!bagel) throw new Error('No bagel provided');
10
+
11
+ return bagel;
12
+ }
13
+
14
+ export interface BagelOptions {
15
+ host: string
16
+ // eslint-disable-next-line no-unused-vars
17
+ onError?: (err: Error) => void
18
+ }
19
+
20
+ export const BagelVue: Plugin = {
21
+ install: (app, options: BagelOptions) => {
22
+ const bagel = new Bagel({ host: options.host, onError: options.onError });
23
+ app.config.globalProperties.$bagel = bagel;
24
+ app.provide(bagelInjectionKey, bagel);
25
+ },
26
+ };
@@ -0,0 +1,90 @@
1
+ .bg-dark {
2
+ position: fixed;
3
+ top: 0;
4
+ right: 0;
5
+ left: 0;
6
+ bottom: 0;
7
+ background-color: rgba(0, 0, 0, 0.7);
8
+ z-index: 999;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ pointer-events: none;
13
+ opacity: 0;
14
+ transition: all ease-in-out 0.3s;
15
+ }
16
+
17
+ .modal {
18
+ width: 96%;
19
+ max-width: 680px;
20
+ transform: scale(0.5);
21
+ opacity: 0;
22
+ transition: all ease-in-out 0.15s;
23
+ overflow: auto;
24
+ max-height: 96vh;
25
+ }
26
+
27
+ .small-modal .modal {
28
+ max-width: 300px;
29
+ text-align: center;
30
+ }
31
+
32
+ .tool-bar {
33
+ margin: -2rem -1rem 1rem;
34
+ display: flex;
35
+ justify-content: space-between;
36
+ position: sticky;
37
+ padding-top: 1rem;
38
+ top: -2rem;
39
+ z-index: 3;
40
+ background: var(--bgl-white);
41
+ }
42
+
43
+ .modal-size {
44
+ cursor: pointer;
45
+ }
46
+
47
+ .is-side .modal {
48
+ inset-inline-end: -600px;
49
+ transform: scale(1);
50
+ opacity: 1;
51
+ position: fixed;
52
+ top: 20px;
53
+ bottom: 20px;
54
+ max-width: 600px;
55
+ width: 90%;
56
+ }
57
+
58
+ .is-active .modal {
59
+ transform: scale(1);
60
+ opacity: 1;
61
+ box-shadow: 6px 6px 20px 20px #0000001c;
62
+ }
63
+
64
+ .is-active.is-side .modal {
65
+ inset-inline-end: 20px;
66
+ }
67
+
68
+ .bg-dark.is-active {
69
+ opacity: 1;
70
+ pointer-events: all;
71
+ }
72
+
73
+ .is-side.bg-dark.is-active {
74
+ opacity: 1;
75
+ }
76
+
77
+ .is-side.is-active .modal {
78
+ pointer-events: all;
79
+ }
80
+
81
+ @media screen and (max-width: 910px) {
82
+ .tool-bar {
83
+ margin: -2rem 0 1rem;
84
+ align-items: center;
85
+ }
86
+
87
+ .is-active.is-side .modal {
88
+ inset-inline-end: 5%;
89
+ }
90
+ }