@bagelink/vue 0.0.378 → 0.0.390

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.
@@ -1,19 +1,18 @@
1
1
  <template>
2
2
  <div class="bagel-input">
3
- <label class="pb-025" >
4
- {{ label }}
3
+ <label class="pb-025">
4
+ {{ label }}
5
5
  </label>
6
6
  <div class="flex gap-05 flex-wrap">
7
- <div class="radio-pill" v-for="({optioId,label,value}, index) in cumputedOptions" :key="index">
7
+ <div class="radio-pill" v-for="(option, index) in options" :key="index">
8
8
  <input
9
9
  type="radio"
10
- :id="optioId"
10
+ :id="getValue(option)"
11
11
  :name="id"
12
- :value="value"
13
- :checked="selectedValue === value"
14
- @change="handleSelect"
15
- >
16
- <label :for="optioId">{{ label }}</label>
12
+ :value="getValue(option)"
13
+ :checked="selectedValue === getValue(option)"
14
+ @change="handleSelect" />
15
+ <label :for="getValue(option)">{{ getLabel(option) }}</label>
17
16
  </div>
18
17
  </div>
19
18
  </div>
@@ -22,27 +21,33 @@
22
21
  <script setup lang="ts">
23
22
  import { onMounted, watch } from 'vue';
24
23
 
25
- interface RadioOption {
26
- optioId: string;
27
- label: string;
28
- value: any;
29
- }
24
+ type Option =
25
+ | string
26
+ | number
27
+ | Record<string, any>
28
+ | { label: string; value: string | number };
29
+
30
30
  const emits = defineEmits(['update:modelValue']);
31
31
 
32
+ const getLabel = (option: Option) => {
33
+ if (typeof option === 'string') return option;
34
+ if (typeof option === 'number') return `${option}`;
35
+ return option.label;
36
+ };
37
+
38
+ const getValue = (option: Option) => {
39
+ if (typeof option === 'string') return option;
40
+ if (typeof option === 'number') return option;
41
+ return option.value;
42
+ };
43
+
32
44
  const props = defineProps<{
33
- options?: RadioOption[],
34
- stringOptions: string[],
35
- modelValue: any,
36
- id?: string,
37
- label?: string,
45
+ options?: Option[];
46
+ modelValue: any;
47
+ id?: string;
48
+ label?: string;
38
49
  }>();
39
50
 
40
- const cumputedOptions = $computed(() => props.options || props.stringOptions.map((v) => ({
41
- optioId: v,
42
- label: v,
43
- value: v,
44
- })));
45
-
46
51
  let selectedValue = $ref('');
47
52
 
48
53
  function handleSelect(e: Event) {
@@ -56,7 +61,7 @@ watch(
56
61
  if (newVal === oldVal || oldVal === undefined) return;
57
62
  if (selectedValue !== newVal) selectedValue = newVal;
58
63
  },
59
- { immediate: true },
64
+ { immediate: true }
60
65
  );
61
66
 
62
67
  onMounted(() => {
@@ -66,30 +71,30 @@ onMounted(() => {
66
71
 
67
72
  <style scoped>
68
73
  .radio-pill label {
69
- color: var(--bgl-primary);
70
- white-space: nowrap;
71
- border-radius: calc(var(--btn-border-radius) * 2);
72
- outline: 1px solid var(--bgl-primary);
73
- padding-left: calc(var(--btn-padding) / 2);
74
- padding-right: calc(var(--btn-padding) / 2);
75
- padding-top: calc(var(--btn-padding) / 6);
76
- padding-bottom: calc(var(--btn-padding) / 6);
77
- cursor: pointer;
78
- transition: var(--bgl-transition);
79
- background: var(--bgl-white);
80
- user-select: none;
74
+ color: var(--bgl-primary);
75
+ white-space: nowrap;
76
+ border-radius: calc(var(--btn-border-radius) * 2);
77
+ outline: 1px solid var(--bgl-primary);
78
+ padding-left: calc(var(--btn-padding) / 2);
79
+ padding-right: calc(var(--btn-padding) / 2);
80
+ padding-top: calc(var(--btn-padding) / 6);
81
+ padding-bottom: calc(var(--btn-padding) / 6);
82
+ cursor: pointer;
83
+ transition: var(--bgl-transition);
84
+ background: var(--bgl-white);
85
+ user-select: none;
81
86
  }
82
87
 
83
88
  .radio-pill label:hover {
84
- filter: var(--bgl-hover-filter);
89
+ filter: var(--bgl-hover-filter);
85
90
  }
86
91
 
87
92
  .radio-pill input {
88
- display: none;
93
+ display: none;
89
94
  }
90
95
 
91
- .radio-pill input:checked~label {
92
- background: var(--bgl-primary);
93
- color: var(--bgl-white);
96
+ .radio-pill input:checked ~ label {
97
+ background: var(--bgl-primary);
98
+ color: var(--bgl-white);
94
99
  }
95
100
  </style>
@@ -2,6 +2,7 @@
2
2
  <div class="RichText">
3
3
  <div class="RichText-tools" v-if="editor">
4
4
  <Btn
5
+ tabindex="-1"
5
6
  :flat="!editor.isActive(item.name, item.option)"
6
7
  @click="item.command"
7
8
  thin
@@ -16,12 +17,21 @@
16
17
  </template>
17
18
 
18
19
  <script setup lang="ts">
19
- import { Btn } from '@bagelink/vue';
20
+ import {
21
+ Btn,
22
+ useModal,
23
+ FileUpload as $el,
24
+ bagelFormUtils,
25
+ BglVideo,
26
+ } from '@bagelink/vue';
20
27
  import { onMounted, onBeforeUnmount, watch } from 'vue';
21
28
  import StarterKit from '@tiptap/starter-kit';
22
29
  import { Editor, EditorContent } from '@tiptap/vue-3';
30
+ import Image from '@tiptap/extension-image';
31
+ import YouTube from '@tiptap/extension-youtube';
23
32
  import type { MaterialIcons } from '@bagelink/vue';
24
-
33
+ // import $el from './FileUploadURL.vue';
34
+ const { txtField } = bagelFormUtils;
25
35
  let editor = $ref<Editor>();
26
36
 
27
37
  const props = defineProps<{ modelValue: string }>();
@@ -30,6 +40,19 @@ const focus = () => {
30
40
  if (!editor) throw new Error('editor is not defined');
31
41
  return editor.chain().focus();
32
42
  };
43
+ const { showModalForm } = useModal();
44
+
45
+ function addImage() {
46
+ showModalForm({
47
+ title: 'Add Image',
48
+ schema: [
49
+ txtField('title', 'Title'),
50
+ { $el, id: 'src', attrs: { bindkey: 'url' } },
51
+ txtField('alt', 'Alt Text'),
52
+ ],
53
+ onSubmit: (imgObj) => focus().setImage(imgObj).run(),
54
+ });
55
+ }
33
56
 
34
57
  const config: {
35
58
  name: string;
@@ -61,11 +84,28 @@ const config: {
61
84
  command: () => focus().toggleCode().run(),
62
85
  icon: 'code',
63
86
  },
64
- // {
65
- // name: 'clearMarks',
66
- // command: () => focus().unsetAllMarks(),
67
- // icon: 'clear',
68
- // },
87
+ {
88
+ name: 'Image',
89
+ command: addImage,
90
+ icon: 'image',
91
+ },
92
+ {
93
+ name: 'YouTube',
94
+ command: () => {
95
+ showModalForm({
96
+ title: 'Add YouTube Video',
97
+ schema: [
98
+ txtField('src', 'YouTube URL'),
99
+ {
100
+ $el: BglVideo,
101
+ attrs: { src: (_, { src }: { src: string }) => src || '' },
102
+ },
103
+ ],
104
+ onSubmit: (videoObj) => editor?.commands.setYoutubeVideo(videoObj),
105
+ });
106
+ },
107
+ icon: 'youtube_activity',
108
+ },
69
109
  {
70
110
  name: 'Clear',
71
111
  command: () => focus().clearNodes().run(),
@@ -160,7 +200,7 @@ const emit = defineEmits(['update:modelValue']);
160
200
 
161
201
  function initEditor() {
162
202
  editor = new Editor({
163
- extensions: [StarterKit],
203
+ extensions: [StarterKit, Image, YouTube],
164
204
  content: props.modelValue,
165
205
  onUpdate: ({ editor }) => emit('update:modelValue', editor.getHTML()),
166
206
  });
@@ -9,6 +9,7 @@ export interface ModalOptions {
9
9
  title?: string;
10
10
  dismissable?: boolean;
11
11
  side?: boolean;
12
+ width?: string;
12
13
  actions?: BtnOptions[];
13
14
  class?: string;
14
15
  visible?: boolean;
@@ -18,6 +19,7 @@ export interface ModalFormOptions {
18
19
  side?: boolean;
19
20
  title?: string;
20
21
  visible?: boolean;
22
+ width?: string;
21
23
  dismissable?: boolean;
22
24
  schema: BglFormSchemaT<any> | (() => BglFormSchemaT) | BglFormSchemaT
23
25
  onSubmit?: (formData: any) => any;
@@ -1,119 +1,119 @@
1
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
- pointer-events: none;
10
- opacity: 0;
11
- transition: all ease-in-out 0.3s;
12
- max-height: 100vh;
13
- overflow: auto;
14
- margin: 0 auto;
15
- width: 100%;
16
- text-align: center;
17
- display: grid;
18
- align-items: center;
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
+ pointer-events: none;
10
+ opacity: 0;
11
+ transition: all ease-in-out 0.3s;
12
+ max-height: 100vh;
13
+ overflow: auto;
14
+ margin: 0 auto;
15
+ width: 100%;
16
+ text-align: center;
17
+ display: grid;
18
+ align-items: center;
19
19
  }
20
20
 
21
21
  .bg-lignt {
22
- background-color: var(--bgl-white);
22
+ background-color: var(--bgl-white);
23
23
  }
24
24
 
25
25
  .modal {
26
- width: 96%;
27
- max-width: 680px;
28
- transform: scale(0.5);
29
- opacity: 0;
30
- transition: all ease-in-out 0.15s;
31
- margin-left: auto;
32
- margin-right: auto;
33
- height: fit-content;
26
+ width: 96%;
27
+ max-width: 720px;
28
+ /* transform: scale(0.5); */
29
+ /* opacity: 0; */
30
+ transition: all ease-in-out 0.18s;
31
+ margin-left: auto;
32
+ margin-right: auto;
33
+ height: fit-content;
34
34
  }
35
35
 
36
36
  .small-modal .modal {
37
- max-width: 300px;
38
- text-align: center;
37
+ max-width: 300px;
38
+ text-align: center;
39
39
  }
40
40
 
41
41
  .tool-bar {
42
- margin: -2rem -1rem 1rem;
43
- display: flex;
44
- justify-content: space-between;
45
- position: -webkit-sticky;
46
- position: sticky;
47
- padding-top: 1rem;
48
- top: 0rem;
49
- z-index: 3;
50
- background: var(--bgl-white);
42
+ margin: -2rem -1rem 1rem;
43
+ display: flex;
44
+ justify-content: space-between;
45
+ position: -webkit-sticky;
46
+ position: sticky;
47
+ padding-top: 1rem;
48
+ top: 0rem;
49
+ z-index: 3;
50
+ background: var(--bgl-white);
51
51
  }
52
52
 
53
53
  .modal-size {
54
- cursor: pointer;
54
+ cursor: pointer;
55
55
  }
56
56
 
57
57
  .is-side .modal {
58
- inset-inline-end: -600px;
59
- transform: scale(1);
60
- opacity: 1;
61
- /* position: fixed; */
62
- /* top: 20px; */
63
- /* bottom: 20px; */
64
- max-width: 600px;
65
- width: 90%;
66
- margin-top: 20px;
67
- margin-bottom: 20px;
68
- margin-inline-start: auto;
69
- margin-inline-end: 20px;
70
- min-height: calc(100vh - 40px);
71
- transform: translateX(100%);
58
+ inset-inline-end: -1720px;
59
+ transform: scale(1);
60
+ opacity: 1;
61
+ /* position: fixed; */
62
+ /* top: 20px; */
63
+ /* bottom: 20px; */
64
+ max-width: 600px;
65
+ width: 90%;
66
+ margin-top: 20px;
67
+ margin-bottom: 20px;
68
+ margin-inline-start: auto;
69
+ margin-inline-end: 20px;
70
+ min-height: calc(100vh - 40px);
71
+ transform: translateX(100%);
72
72
  }
73
73
 
74
74
  .is-active .modal {
75
- transform: scale(1);
76
- opacity: 1;
77
- box-shadow: 6px 6px 20px 20px #0000001c;
75
+ transform: scale(1);
76
+ opacity: 1;
77
+ box-shadow: 6px 6px 20px 20px #0000001c;
78
78
  }
79
79
 
80
80
  .bg-lignt .modal {
81
- transform: scale(1);
82
- border: 1px solid var(--border-color);
81
+ transform: scale(1);
82
+ border: 1px solid var(--border-color);
83
83
  }
84
84
 
85
85
  .bg-lignt.is-active .modal {
86
- box-shadow: none;
86
+ box-shadow: none;
87
87
  }
88
88
 
89
89
  .is-active.is-side .modal {
90
- inset-inline-end: 20px;
91
- transform: translateX(0%);
90
+ inset-inline-end: 0px;
91
+ transform: translateX(0%);
92
92
  }
93
93
 
94
94
  .bg-dark.is-active {
95
- opacity: 1;
96
- pointer-events: all;
95
+ opacity: 1;
96
+ pointer-events: all;
97
97
  }
98
98
 
99
99
  .is-side.bg-dark.is-active {
100
- opacity: 1;
101
- align-items: stretch;
100
+ opacity: 1;
101
+ align-items: stretch;
102
102
  }
103
103
 
104
104
  .is-side.is-active .modal {
105
- pointer-events: all;
105
+ pointer-events: all;
106
106
  }
107
107
 
108
108
  @media screen and (max-width: 910px) {
109
- .tool-bar {
110
- margin: -1rem 0rem 1rem;
111
- padding-bottom: 1rem;
112
- align-items: center;
113
- }
109
+ .tool-bar {
110
+ margin: -1rem 0rem 1rem;
111
+ padding-bottom: 1rem;
112
+ align-items: center;
113
+ }
114
114
 
115
- .is-active.is-side .modal {
116
- margin-inline-end: 5%;
117
- margin-inline-start: 5%;
118
- }
115
+ .is-active.is-side .modal {
116
+ margin-inline-end: 5%;
117
+ margin-inline-start: 5%;
118
+ }
119
119
  }