@zipify/wysiwyg 3.5.0-ai-prototype → 3.5.0

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,204 +0,0 @@
1
- <template>
2
- <div class="zw-position--relative">
3
- <FloatingMenu
4
- :should-show="shouldShow"
5
- v-if="editor"
6
- :editor="editor"
7
- ref="floatingMenu"
8
-
9
- :tippy-options="menuOptions"
10
- >
11
- <Button icon class="zw-floating-menu__button" :active="isActive" @click="toggler.open" v-tooltip="'Write with AI'">
12
- <Icon name="sparkles" size="24px" />
13
- </Button>
14
- </FloatingMenu>
15
-
16
- <Modal class="zw-link-modal" :toggler="toggler" ref="modalRef" focus-first-control>
17
- <form class="zw-link-modal__body" @submit.prevent="generateText">
18
- <div class="zw-link-form__body">
19
- Selected text:
20
- <p class="zw-ai-component__selected-text">
21
- {{ selectedText }}
22
- </p>
23
-
24
- <template v-if="suggestions.length || isLoading">
25
- <p class="zw-margin-bottom--xs">
26
- Suggestions:
27
- </p>
28
- <AiWidgetSuggestionItem
29
- v-for="suggestion of suggestions"
30
- :suggestion="suggestion"
31
- :key="suggestion.result"
32
- @close="toggler.close"
33
- />
34
-
35
- <AiWidgetSuggestionItem v-if="isLoading" :suggestion="{ content: 'Working on it...', state: 'loading' }" />
36
- </template>
37
-
38
- </div>
39
-
40
- <div class="zw-position--relative">
41
- <input v-model="prompt" type="text" class="zw-ai-component__input" placeholder="Tell us to ...">
42
-
43
- <Button type="submit" class="zw-ai-component__send-button">
44
- <Icon auto-color class="zw-ai-component__icon" :name="iconName" size="32px" />
45
- </Button>
46
- </div>
47
- </form>
48
- </Modal>
49
- </div>
50
- </template>
51
-
52
- <script>
53
- import { inject, ref, unref, computed } from 'vue';
54
- import { FloatingMenu } from '@tiptap/vue-2';
55
- import { Button, Icon, Modal, useModalToggler } from '../base';
56
- import { InjectionTokens } from '../../injectionTokens';
57
- import { tooltip } from '../../directives';
58
- import AiWidgetSuggestionItem from './AiWidgetSuggestionItem';
59
-
60
- export default {
61
- name: 'FloatingMenuControl',
62
-
63
- components: {
64
- AiWidgetSuggestionItem,
65
- FloatingMenu,
66
- Icon,
67
- Button,
68
- Modal
69
- },
70
-
71
- directives: {
72
- tooltip
73
- },
74
-
75
- setup() {
76
- const editor = inject(InjectionTokens.EDITOR);
77
- const suggestions = ref([]);
78
- const wrapperRef = ref(null);
79
- const floatingMenu = ref(null);
80
- const modalRef = ref(null);
81
- const prompt = ref('');
82
- const isLoading = ref(false);
83
-
84
- const selectedText = computed(() => editor.commands.getSelectedText());
85
-
86
- const iconName = computed(() => {
87
- return unref(isLoading) ? 'loading' : 'send';
88
- });
89
-
90
- const onBeforeOpened = () => {
91
- suggestions.value = [];
92
- };
93
-
94
- const toggler = useModalToggler({
95
- onBeforeOpened: () => onBeforeOpened(),
96
- wrapperRef: floatingMenu,
97
- modalRef
98
- });
99
-
100
- const isActive = computed(() => unref(toggler.isOpened));
101
-
102
- const shouldShow = () => {
103
- return selectedText.value.length > 1;
104
- };
105
-
106
- const generateText = async () => {
107
- if(isLoading.value) return;
108
-
109
- isLoading.value = true;
110
- const lastSuggestions = suggestions.value[suggestions.value.length - 1];
111
-
112
- const context = lastSuggestions ? lastSuggestions.content : selectedText.value;
113
-
114
- const result = await editor.commands.generateText({ prompt: prompt.value, context });
115
-
116
- isLoading.value = false;
117
- suggestions.value.push(result);
118
- };
119
-
120
- const menuOptions = {
121
- placement: 'right-end',
122
- offset: [0, 10]
123
- };
124
-
125
- return {
126
- selectedText,
127
- editor,
128
- floatingMenu,
129
- shouldShow,
130
- menuOptions,
131
- toggler,
132
- wrapperRef,
133
- modalRef,
134
- isActive,
135
- generateText,
136
- suggestions,
137
- prompt,
138
- iconName,
139
- isLoading
140
- };
141
- }
142
- };
143
- </script>
144
-
145
- <style scoped>
146
- .zw-floating-menu__button {
147
- padding: 2px;
148
- background-color: rgba(255, 252, 252, 1);
149
- border-radius: 50%;
150
- box-shadow: 0 0 0 0 1px #878DA2;
151
- }
152
-
153
- .zw-link-modal {
154
- width: 450px;
155
- background-color: #FCFCFC;
156
- border-radius: 8px;
157
- box-shadow: 0 0 0 0.5px #878DA2, 0 0 2px 0.5px rgba(135, 141, 162, 0.5), 0 1px 8px 0.5px rgba(135, 141, 162, 0.1), 0 2px 12px 0.5px rgba(135, 141, 162, 0.1), 0 4px 20 0.5px rgba(135, 141, 162, 0.25);
158
- }
159
-
160
- .zw-link-modal__body {
161
- padding: var(--zw-offset-sm);
162
- }
163
-
164
- .zw-link-form__body {
165
- overscroll-behavior: contain;
166
- overflow: auto;
167
- max-height: max(min(calc(1051.21px - calc(calc(3.5px * 16) + 47.9844px) - calc(0.25px * 16)), calc(34.75px * 16)), calc(10px * 16));
168
- }
169
-
170
- .zw-ai-component__selected-text {
171
- font-size: 14px;
172
- margin-bottom: 8px;
173
- padding: 16px 8px;
174
- background-color: #FFF;
175
- border: 0.5px solid #000;
176
- border-radius: 2px;
177
- }
178
-
179
- .zw-ai-component__input {
180
- width: 100%;
181
- min-height: 40px;
182
- border: 1px solid #E9E9E9;
183
- border-radius: 5px;
184
- padding: 8px;
185
- font-size: 14px;
186
- }
187
-
188
- .zw-ai-component__send-button {
189
- position: absolute;
190
- top: 50%;
191
- transform: translateY(-50%);
192
- right: 16px;
193
- }
194
-
195
- .zw-ai-component__icon {
196
- color: #CDD1DC;
197
- }
198
-
199
- .zw-ai-component__send-button:hover .zw-ai-component__icon {
200
- color: #878DA2;
201
- transition: color 0.1s ease-in-out;
202
- }
203
- </style>
204
-
@@ -1 +0,0 @@
1
- export { default as FloatingMenuControl } from './FloatingMenuControl';
@@ -1,185 +0,0 @@
1
- <template>
2
- <div class="zw-position--relative" ref="wrapperRef">
3
- <Button icon skin="toolbar" :active="isActive" @click="toggler.open" v-tooltip="'Generate text'">
4
- <Icon name="sparkles" size="28px" />
5
- </Button>
6
-
7
- <Modal class="zw-suggestion-modal" :toggler="toggler" ref="modalRef" focus-first-control>
8
-
9
- <AiControlHeader />
10
- <form class="zw-link-modal__body" @submit.prevent="generateText">
11
-
12
- <AiSuggestionItem
13
- v-if="isLoading"
14
- :suggestion="{ content: 'Working on it...', state: 'loading' }"
15
- />
16
-
17
- <AiSuggestionItem
18
- v-else-if="lastSuggestions"
19
- :suggestion="lastSuggestions"
20
- />
21
-
22
- <label class="zw-field__label">
23
- {{ textAreaLabel }}
24
- </label>
25
-
26
- <div class="zw-position--relative">
27
- <TextArea
28
- class="zw-margin-bottom--sm"
29
- v-model="prompt"
30
- />
31
- <Button type="submit" class="zw-ai-component__send-button">
32
- <Icon auto-color class="zw-ai-component__icon" name="send" size="32px" />
33
- </Button>
34
- </div>
35
-
36
- <Button :disabled="!lastSuggestions" type="button" skin="primary" @click="applyText">
37
- Apply
38
- </Button>
39
- </form>
40
-
41
-
42
- </Modal>
43
- </div>
44
- </template>
45
-
46
- <script>
47
- import { computed, ref, inject, unref } from 'vue';
48
- import { InjectionTokens } from '../../../../injectionTokens';
49
- import { tooltip } from '../../../../directives';
50
- import { Button, Icon, Modal, TextArea, useModalToggler } from '../../../base';
51
- import AiControlHeader from './AiControlHeader';
52
- import AiSuggestionItem from './AiSuggestionItem';
53
-
54
- export default {
55
- name: 'AiControl',
56
-
57
- components: {
58
- Modal,
59
- Icon,
60
- Button,
61
- TextArea,
62
- AiControlHeader,
63
- AiSuggestionItem
64
- },
65
-
66
- directives: {
67
- tooltip
68
- },
69
-
70
- setup() {
71
- const wrapperRef = ref(null);
72
- const modalRef = ref(null);
73
-
74
- const prompt = ref('');
75
- const suggestions = ref([]);
76
- const isLoading = ref(false);
77
-
78
- const textAreaLabel = computed(() => {
79
- return suggestions.value.length ? 'Tell AI what to do next…' : 'Write you request';
80
- });
81
-
82
- const lastSuggestions = computed(() => suggestions.value[suggestions.value.length - 1]);
83
-
84
- const editor = inject(InjectionTokens.EDITOR);
85
-
86
- const onBeforeOpened = () => {};
87
-
88
- const toggler = useModalToggler({
89
- onBeforeOpened: () => onBeforeOpened(),
90
- wrapperRef,
91
- modalRef
92
- });
93
-
94
- const onAction = async (action) => {
95
- isLoading.value = true;
96
-
97
- const lastSuggestions = suggestions.value[suggestions.value.length - 1];
98
-
99
- const context = lastSuggestions ? lastSuggestions.content : '';
100
-
101
- const result = await editor.commands.generateText({ prompt: action, context });
102
-
103
- isLoading.value = false;
104
- suggestions.value.push(result);
105
- };
106
-
107
- const generateText = async () => {
108
- if(isLoading.value) return;
109
-
110
- isLoading.value = true;
111
-
112
- const lastSuggestions = suggestions.value[suggestions.value.length - 1];
113
-
114
- const context = lastSuggestions ? lastSuggestions.content : '';
115
-
116
- const result = await editor.commands.generateText({ prompt: prompt.value, context });
117
-
118
- isLoading.value = false;
119
- prompt.value = '';
120
- suggestions.value.push(result);
121
- };
122
-
123
- const applyText = () => {
124
- editor.commands.setContent(lastSuggestions.value.content);
125
- toggler.close();
126
- suggestions.value = [];
127
- prompt.value = '';
128
- };
129
-
130
- const isActive = computed(() => unref(toggler.isOpened));
131
-
132
- return {
133
- wrapperRef,
134
- modalRef,
135
- toggler,
136
- isActive,
137
- prompt,
138
- generateText,
139
- lastSuggestions,
140
- textAreaLabel,
141
- isLoading,
142
- onAction,
143
- applyText
144
- };
145
- }
146
- };
147
- </script>
148
-
149
- <style scoped>
150
- .zw-suggestion-modal {
151
- width: 500px;
152
- }
153
-
154
- .zw-link-modal__body {
155
- padding: var(--zw-offset-sm);
156
- }
157
-
158
- .zw-generated-text__suggestion {
159
- font-size: 14px;
160
- color: #908E8E;
161
- }
162
-
163
- .zw-ai-component__send-button {
164
- position: absolute;
165
- top: 50%;
166
- transform: translateY(-50%);
167
- right: 16px;
168
- }
169
-
170
- .zw-ai-component__icon {
171
- color: #CDD1DC;
172
- }
173
-
174
- .zw-ai-component__send-button:hover .zw-ai-component__icon {
175
- color: #878DA2;
176
- transition: color 0.1s ease-in-out;
177
- }
178
-
179
- .zw-field__label {
180
- display: inline-block;
181
- font-size: var(--zw-font-size-xxs);
182
- padding-bottom: var(--zw-offset-xxs);
183
- line-height: var(--zw-line-height-xxs);
184
- }
185
- </style>
@@ -1,28 +0,0 @@
1
- <template>
2
- <div class="zw-link-modal-header">
3
- <span class="zw-link-modal-header__title">Generate text</span>
4
- </div>
5
- </template>
6
-
7
- <script>
8
- export default {
9
- name: 'AiControlHeader'
10
- };
11
- </script>
12
-
13
- <style scoped>
14
- .zw-link-modal-header {
15
- display: flex;
16
- align-items: center;
17
- justify-content: space-between;
18
- padding: var(--zw-offset-sm);
19
- border-bottom: 2px solid rgb(var(--zw-color-n5));
20
- }
21
-
22
- .zw-link-modal-header__title {
23
- text-transform: uppercase;
24
- font-weight: var(--zw-font-weight-semibold);
25
- font-size: var(--zw-font-size-xxs);
26
- color: rgb(var(--zw-color-white));
27
- }
28
- </style>
@@ -1,74 +0,0 @@
1
- <template>
2
- <div class="zw-ai-component__suggestion">
3
- <p v-if="!isLoading" class="zw-ai-component-suggestion__request zw-margin-bottom--sm">
4
- {{ suggestion.request }}
5
- </p>
6
- <p :class="{'zw-margin-bottom--sm': !isLoading }" v-html="suggestion.content" />
7
-
8
- <Button type="button" v-if="!isLoading" @click="sendAction('Rewrite text')" class="zw-ai-component-suggestion__button">
9
- ✍ Rewrite text
10
- </Button>
11
- </div>
12
- </template>
13
-
14
- <script>
15
- import { inject, computed } from 'vue';
16
- import { Button } from '../../../base';
17
- import { InjectionTokens } from '../../../../injectionTokens';
18
-
19
- export default {
20
- name: 'AiSuggestionItem',
21
-
22
- components: {
23
- Button
24
- },
25
-
26
- props: {
27
- suggestion: {
28
- type: Object,
29
- required: true
30
- }
31
- },
32
-
33
- setup(props, { emit }) {
34
- const isLoading = computed(() => props.suggestion.state === 'loading');
35
-
36
- const sendAction = (action) => {
37
- emit('action', action);
38
- };
39
-
40
- return {
41
- isLoading,
42
- sendAction
43
- };
44
- }
45
- };
46
- </script>
47
-
48
- <style scoped>
49
- .zw-ai-component__suggestion {
50
- font-size: 14px;
51
- margin-bottom: 8px;
52
- padding: 16px 8px;
53
- color: #CDD1DC;
54
- border-radius: 2px;
55
- }
56
-
57
- .zw-ai-component-suggestion__request {
58
- font-size: 12px;
59
- color: #666;
60
- }
61
-
62
- .zw-ai-component-suggestion__button {
63
- font-size: 14px;
64
- padding: 4px 8px;
65
- background-color: #A4A4A4;
66
- color: #FFF;
67
- border-radius: 2px;
68
- }
69
-
70
- .zw-ai-component-suggestion__button:hover {
71
- opacity: 0.8;
72
- background-color: #3AAA35;
73
- }
74
- </style>
@@ -1,21 +0,0 @@
1
- import { toRef } from 'vue';
2
- import { Extension } from '@tiptap/vue-2';
3
- import { createCommand } from '../utils';
4
-
5
- export const AiComponent = Extension.create({
6
- name: 'device_manager',
7
-
8
- addCommands() {
9
- return {
10
- // _getAiAdapter: createCommand(() => toRef(this.options, 'device'))
11
-
12
- generateText: createCommand(async ({ commands }, { prompt, context }) => {
13
- const aiComponent = this.options.aiComponent;
14
- const result = await aiComponent.generateText({ prompt, context });
15
-
16
- result.content = result.content.replace(/\n/g, '');
17
- return result;
18
- })
19
- };
20
- }
21
- });