@bagelink/vue 0.0.22 → 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,290 @@
1
+ <template>
2
+ <div class="bar-chart">
3
+ <div class="graph-wrap" v-for="(item, i) in dataArray" :key="i">
4
+ <div class="group-wrap" v-if="item.group">
5
+ <p class="group-title">
6
+ {{ item.group }}
7
+ </p>
8
+ <div v-for="(nested, i) in item?.data || []" :key="i" class="bar-wrap">
9
+ <div class="bar" :style="{ height: loaded ? `${percent(nested.value)}%` : '0' }" />
10
+ <div
11
+ class="bar compare" v-if="nested.compareValue" :style="{
12
+ height: loaded ? `${percent(nested.compareValue)}%` : '0',
13
+ }"
14
+ />
15
+ <!-- <p class="bar-txt">{{ nested.title }}</p> -->
16
+ </div>
17
+ </div>
18
+ <div v-else class="bar-wrap">
19
+ <div class="bar" :style="{ height: loaded ? `${percent(item.value)}%` : '0' }" />
20
+ <div
21
+ class="bar compare" v-if="item?.compareValue"
22
+ :style="{ height: loaded ? `${percent(item.compareValue)}%` : '0' }"
23
+ />
24
+ <p class="bar-txt">
25
+ {{ item.title }}
26
+ </p>
27
+ </div>
28
+ </div>
29
+ <p class="factor">
30
+ {{ title }}
31
+ </p>
32
+ <div class="red-bar" />
33
+ <div class="bar-lines">
34
+ <p v-for="mark in marks" :key="mark">
35
+ {{ mark.toLocaleString() }}
36
+ </p>
37
+ </div>
38
+ </div>
39
+ </template>
40
+
41
+ <script setup lang="ts">
42
+ import { ref, onMounted, computed } from 'vue';
43
+
44
+ const props = defineProps<{
45
+ title?: string;
46
+ showMarks?: boolean;
47
+ flood?: number;
48
+ modelValue: {
49
+ value: number;
50
+ title?: string;
51
+ compareValue?: number;
52
+ group?: string;
53
+ data?: Record<string, any>[];
54
+ }[];
55
+ // | {
56
+ // group: string;
57
+ // data: {
58
+ // value: number;
59
+ // title: string;
60
+ // compareValue?: number | undefined;
61
+ // group?: string | undefined;
62
+ // data?: Record<string, any>[] | undefined;
63
+ // }[]
64
+ // }[]
65
+ }>();
66
+ const loaded = ref(false);
67
+
68
+ onMounted(() => {
69
+ setTimeout(() => {
70
+ loaded.value = true;
71
+ }, 400);
72
+ });
73
+
74
+ const dataArray = computed(
75
+ () => props.modelValue,
76
+ // const allData = []
77
+ // for (const item of props.modelValue) {
78
+ // if (item.group) {
79
+ // let groupIndex = allData.findIndex(d => d.group === item.group)
80
+ // if (groupIndex > -1) allData[groupIndex].data?.push(item);
81
+ // else allData.push({ group: item.group, data: [item] })
82
+ // } else {
83
+ // allData.push(item)
84
+ // }
85
+ // }
86
+ // return allData;
87
+ );
88
+
89
+ const maxValue = computed(() => Math.ceil(
90
+ Math.max(
91
+ ...dataArray.value.map((d) => d.value),
92
+ ...dataArray.value.map((d) => d?.compareValue || 0),
93
+ ),
94
+ ));
95
+
96
+ const marks = computed(() => {
97
+ const marksArray: number[] = [];
98
+ for (let i = 0; i <= 5; i += 1) {
99
+ const step = (i * maxValue.value) / 5;
100
+ marksArray.push(Math.round(step / 10) * 10);
101
+ }
102
+ return marksArray;
103
+ });
104
+
105
+ const percent = (val: number) => (val / maxValue.value) * 100;
106
+ const floodPercent = computed(() => `${props.flood}%`);
107
+ </script>
108
+
109
+ <style scoped>
110
+ /* .group-wrap * {
111
+ outline: 1px solid red;
112
+ } */
113
+
114
+ .group-wrap {
115
+ height: 100%;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ flex-wrap: wrap;
120
+ gap: 2px;
121
+ }
122
+
123
+ .group-wrap .bar-wrap {
124
+ gap: 2px;
125
+ }
126
+
127
+ .group-title {
128
+ font-size: 0.6em;
129
+ width: 100%;
130
+ }
131
+
132
+ .bar-txt {
133
+ font-size: 11px;
134
+ font-weight: 200;
135
+ /* max-width: 95%; */
136
+ width: max-content;
137
+ height: 20px;
138
+ line-height: 1.2;
139
+ margin: 5px auto 0;
140
+ position: absolute;
141
+ transform: rotate(300deg);
142
+ transform-origin: 40px 40px;
143
+ }
144
+
145
+ .graph-wrap {
146
+ display: flex;
147
+ flex-direction: row;
148
+ align-items: flex-end;
149
+ padding: 0 10px;
150
+ }
151
+
152
+ .bar-wrap {
153
+ text-align: center;
154
+ height: 100%;
155
+ /* flex: 0 1 16.6%; */
156
+ display: flex;
157
+ flex-direction: row;
158
+ align-items: flex-end;
159
+ position: relative;
160
+ }
161
+
162
+ .bar {
163
+ background: var(--bgl-blue);
164
+ position: relative;
165
+ min-width: 10px;
166
+ min-height: 5px;
167
+ width: 4px;
168
+ margin: 0 auto;
169
+ transition: all ease-out 0.8s;
170
+ }
171
+
172
+ .bar.compare {
173
+ background-color: #cf2135;
174
+ }
175
+
176
+ .bar-chart {
177
+ height: calc(100vh - 500px);
178
+ width: 90%;
179
+ margin: 30px auto;
180
+ display: flex;
181
+ justify-content: space-between;
182
+ position: relative;
183
+ }
184
+
185
+ .graps .bar-chart {
186
+ aspect-ratio: 9/5;
187
+ height: auto;
188
+ max-height: calc(100vh - 500px);
189
+ }
190
+
191
+ .bar-lines {
192
+ position: absolute;
193
+ /* font-size: 20px; */
194
+ display: flex;
195
+ flex-direction: column-reverse;
196
+ top: -15px;
197
+ bottom: -12px;
198
+ left: -30px;
199
+ justify-content: space-between;
200
+ width: calc(100% + 20px);
201
+ text-align: start;
202
+ }
203
+
204
+ .bar-lines p {
205
+ margin: 0;
206
+ position: relative;
207
+ }
208
+
209
+ .bar-lines p::after {
210
+ content: "";
211
+ background: var(--bgl-blue-tint);
212
+ height: 1px;
213
+ position: absolute;
214
+ width: calc(100% - 20px);
215
+ margin: 14px 0 0 10px;
216
+ opacity: 0.5;
217
+ }
218
+
219
+ .bar-lines p:first-child:after {
220
+ content: "";
221
+ background: var(--bgl-blue-tint);
222
+ height: 1px;
223
+ position: absolute;
224
+ width: calc(100% - 10px);
225
+ margin: 8px 0 0 10px;
226
+ opacity: 0.5;
227
+ }
228
+
229
+ .red-bar {
230
+ background: #cf2135;
231
+ height: v-bind(floodPercent);
232
+ width: 100%;
233
+ position: absolute;
234
+ left: 0px;
235
+ bottom: 0;
236
+ opacity: 0.6;
237
+ transition: all 200ms ease;
238
+ }
239
+
240
+ .red-bar.open-redbar {
241
+ height: 7%;
242
+ }
243
+
244
+ .factor {
245
+ position: absolute;
246
+ transform: rotate(270deg);
247
+ height: 0px;
248
+ width: 0;
249
+ left: -60px;
250
+ font-size: 22px;
251
+ text-align: center;
252
+ white-space: nowrap;
253
+ top: 60%;
254
+ }
255
+
256
+ .dash-hor {
257
+ /* border-bottom: 1px dashed white; */
258
+ position: absolute;
259
+ background-image: linear-gradient(to right, #cf2134 53%, transparent 0%);
260
+ height: 10px;
261
+ bottom: 41.5%;
262
+ width: 100%;
263
+ animation: 1s linear 0s infinite dash;
264
+ background-position: left;
265
+ background-repeat: repeat-x;
266
+ background-size: 15px 4px;
267
+ }
268
+
269
+ .dash-hor::after {
270
+ content: "Average Speedup = 25x";
271
+ position: absolute;
272
+ left: 0;
273
+ bottom: 10px;
274
+ font-size: 22px;
275
+ background: #cf2134;
276
+ z-index: 2;
277
+ padding: 1px 4px;
278
+ border-radius: 3px;
279
+ }
280
+
281
+ @keyframes dash {
282
+ 0% {
283
+ background-position: 0;
284
+ }
285
+
286
+ 100% {
287
+ background-position: 15px;
288
+ }
289
+ }
290
+ </style>
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <div ref="chartContainer" class="chart-line">
3
+ <Chart v-if="chartSize" :size="chartSize" :data="data" :margin="chartMargin" :axis="axisConfig">
4
+ <template #layers>
5
+ <Grid :center="true" strokeDasharray="2,2" :hideY="true" />
6
+ <Area
7
+ aria-label="Profit/Loss" :dataKeys="['date', 'total_value']" type="monotone"
8
+ :areaStyle="{ fill: 'url(#grad)' }"
9
+ />
10
+ <Line
11
+ :dataKeys="['date', 'total_value']" type="monotone" :dotStyle="dotStyling"
12
+ :lineStyle="{ stroke: BRAND_COLOR, r: 2 }"
13
+ />
14
+ <Marker
15
+ v-if="displayMarker" :value="meanValue" label="ממוצע" :color="BRAND_COLOR" :strokeWidth="2"
16
+ strokeDasharray="6 6"
17
+ />
18
+ <defs>
19
+ <linearGradient id="grad" gradientTransform="rotate(90)">
20
+ <stop offset="0%" :stop-color="BRAND_COLOR" stop-opacity="1" />
21
+ <stop offset="100%" stop-color="white" stop-opacity="0.4" />
22
+ </linearGradient>
23
+ </defs>
24
+ </template>
25
+ <template #widgets>
26
+ <Tooltip color="white" :config="tooltipConfiguration" />
27
+ </template>
28
+ </Chart>
29
+ </div>
30
+ </template>
31
+
32
+ <script lang="ts" setup>
33
+ import { onMounted, onUnmounted } from 'vue';
34
+ import { useI18n } from 'vue-i18n';
35
+ import {
36
+ Chart, Grid, Line, Area, Tooltip, Marker,
37
+ } from 'vue3-charts';
38
+ import type { ChartAxis, Data } from 'vue3-charts/dist/types';
39
+
40
+ const props = defineProps<{ data: Data[] }>();
41
+
42
+ const { locale } = useI18n();
43
+
44
+ const data = $computed(() => (locale.value === 'he' ? [...props.data].reverse() : props.data));
45
+
46
+ interface Size {
47
+ width: number;
48
+ height: number;
49
+ }
50
+
51
+ // Computed properties
52
+ const meanValue = $computed(() => {
53
+ const sum = props.data.reduce((acc, curr) => acc + +curr.total_value, 0);
54
+ return sum / props.data.length;
55
+ });
56
+
57
+ const axisConfig = $computed<ChartAxis>(() => ({
58
+ primary: {
59
+ type: 'band',
60
+ rotate: true,
61
+ ticks: 5,
62
+ domain: ['dataMin', 'dataMax'],
63
+ tickValues: props.data?.length > 100 ? [''] : props.data.map((d: any) => d.date),
64
+ },
65
+ secondary: {
66
+ domain: ['dataMin', 'dataMax * 1.05'],
67
+ type: 'linear',
68
+ ticks: 8,
69
+ },
70
+ }));
71
+
72
+ // Constants
73
+ const BRAND_COLOR = 'var(--bgl-blue)';
74
+
75
+ const tooltipConfiguration = {
76
+ date: { label: 'תאריך' },
77
+ total_value: { color: BRAND_COLOR, label: 'סכום', format: (v: number) => `₪${v.toLocaleString()}` },
78
+ total_count: { label: 'מספר התרומות', format: (v: number) => `${v.toLocaleString()}` },
79
+ };
80
+
81
+ // Refs
82
+ let chartSize = $ref<Size | null>(null);
83
+ const chartContainer = $ref<HTMLElement>();
84
+ const displayMarker = $ref(true);
85
+ const chartMargin = $ref({
86
+ left: 0,
87
+ top: 0,
88
+ right: 0,
89
+ bottom: 0,
90
+ });
91
+
92
+ // Functions
93
+ const adjustChartSize = () => {
94
+ chartSize = null;
95
+ const el = chartContainer;
96
+ if (!el) return;
97
+ const { width, height } = el.getBoundingClientRect();
98
+ chartSize = { width: width - 5, height: height - 10 };
99
+ console.log(chartSize);
100
+ };
101
+
102
+ const handleResize = () => {
103
+ setTimeout(adjustChartSize, 300);
104
+ };
105
+
106
+ // Lifecycle hooks
107
+ onMounted(() => {
108
+ adjustChartSize();
109
+ window.addEventListener('resize', handleResize);
110
+ });
111
+
112
+ onUnmounted(() => {
113
+ window.removeEventListener('resize', handleResize);
114
+ });
115
+
116
+ // Style Configurations
117
+ const dotStyling = (ctx: Record<string, any>) => ({
118
+ r: ctx.active ? 5 : 1,
119
+ fill: BRAND_COLOR,
120
+ });
121
+ </script>
122
+
123
+ <style>
124
+ .chart-line {
125
+ width: 100%;
126
+ height: 300px;
127
+ }
128
+
129
+ [dir='rtl'] .chart-line {
130
+ direction: ltr;
131
+ }
132
+
133
+ .chart-line .v-tooltip-content>div {
134
+ border: none !important;
135
+ border-radius: 6px !important;
136
+ background-color: black !important;
137
+ opacity: 0.7;
138
+ padding: 0.5rem 1rem !important;
139
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06) !important;
140
+ font-weight: 300;
141
+ }
142
+
143
+ .chart-line .v-tooltip-content>div b {
144
+ font-weight: 400;
145
+ }
146
+
147
+ .layer-grid g:last-child {
148
+ display: none;
149
+ }
150
+
151
+ .layer-axis-x .tick:nth-child(2n + 1) {
152
+ opacity: 0;
153
+ }
154
+
155
+ @media screen and (max-width: 910px) {
156
+ .chart-line {
157
+ height: 140px;
158
+ }
159
+
160
+ .layer-axis-x .tick {
161
+ opacity: 0;
162
+ font-size: 0;
163
+ }
164
+ }
165
+ </style>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div>
3
+ {{ field.label || field.id }}
4
+
5
+ <Btn color="gray" @click="openModal()" v-if="field.refCollection">
6
+ {{ content }}
7
+ <MaterialIcon icon="arrow_forward" />
8
+ </Btn>
9
+ <span v-else class="pill">
10
+ {{ content }}
11
+ </span>
12
+ </div>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ import { ref, computed } from 'vue';
17
+ import { useRouter } from 'vue-router';
18
+ import type { BagelField } from '@/types';
19
+ import { Btn, MaterialIcon } from '@/components';
20
+
21
+ const router = useRouter();
22
+ // import Modal from '@/components/Modal.vue';
23
+
24
+ const openRef = ref(false);
25
+
26
+ const props = defineProps<{
27
+ modelValue: Record<string, any>;
28
+ field: BagelField;
29
+ }>();
30
+
31
+ const content = computed(() => props.field.refFields?.map((k) => props.modelValue?.[k] || '').join(' '));
32
+
33
+ const openModal = () => {
34
+ console.log(`openning ${props.modelValue?.id}`);
35
+ openRef.value = true;
36
+ router.push(`/${props.field.refCollection}/${props.modelValue?.id}`);
37
+ };
38
+ </script>
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <div
3
+ class="icon-font"
4
+ :style="{ fontSize: `${size}rem` }"
5
+ >
6
+ {{ icon }}
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { MaterialIcons } from '../../types/materialIcons';
12
+
13
+ defineProps<{
14
+ icon: MaterialIcons
15
+ size?: number
16
+ }>();
17
+ </script>
18
+
19
+ <style scoped></style>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="bagel-input">
3
+ <label :for="formatString(name, 'pascal')">
4
+ <LangText :input="formatString(name, 'titleCase')" />
5
+ </label>
6
+ <input
7
+ v-if="type === 'checkbox'"
8
+ ref="el"
9
+ :checked="modelValue"
10
+ class="ctl"
11
+ type="checkbox"
12
+ @change="handleCheck"
13
+ >
14
+ <input
15
+ v-else-if="type === 'number'"
16
+ ref="el"
17
+ :name="formatString(name, 'pascal')"
18
+ :type="type"
19
+ :value="modelValue"
20
+ class="ctl"
21
+ @input="handleInput"
22
+ >
23
+ <input
24
+ v-else-if="type === 'text'"
25
+ ref="el"
26
+ :name="formatString(name, 'pascal')"
27
+ :type="type"
28
+ :value="modelValue"
29
+ class="ctl"
30
+ @input="handleInput"
31
+ >
32
+ <textarea
33
+ v-else-if="type === 'textarea'"
34
+ ref="el"
35
+ :name="formatString(name, 'pascal')"
36
+ :type="type"
37
+ :value="modelValue"
38
+ class="ctl"
39
+ @input="handleInput"
40
+ />
41
+ <div>
42
+ <LangText :input="errorMessage" />
43
+ </div>
44
+ </div>
45
+ </template>
46
+
47
+ <script lang="ts" setup>
48
+ import { onMounted, ref } from 'vue';
49
+ // @ts-ignore TODO: remove this
50
+ import { formatString } from '../../composables';
51
+ // @ts-ignore TODO: remove this
52
+ import LangText from '../translation/LangText.vue';
53
+
54
+ const props = defineProps<{
55
+ type: 'text' | 'number' | 'password' | 'email' | 'checkbox' | 'textarea';
56
+ name: string;
57
+ value?: any;
58
+ modelValue: any;
59
+ errorMessage?: string;
60
+ focus?: boolean;
61
+ }>();
62
+
63
+ const emits = defineEmits(['update:modelValue']);
64
+ const el = ref<HTMLInputElement | null>(null);
65
+ const handleInput = (e: Event) => {
66
+ const el = e.target as HTMLInputElement;
67
+ emits('update:modelValue', el.value);
68
+ };
69
+ const handleCheck = (e: Event) => {
70
+ const el = e.target as HTMLInputElement;
71
+ emits('update:modelValue', el.checked ? 1 : 0);
72
+ };
73
+ onMounted(() => {
74
+ if (props.focus) {
75
+ el.value?.focus();
76
+ }
77
+ });
78
+ </script>
79
+
80
+ <style scoped></style>