pimelon-ui 0.0.98

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 (93) hide show
  1. package/license.md +0 -0
  2. package/package.json +75 -0
  3. package/readme.md +0 -0
  4. package/src/components/Alert.vue +57 -0
  5. package/src/components/Autocomplete.vue +176 -0
  6. package/src/components/Avatar.vue +62 -0
  7. package/src/components/Badge.vue +42 -0
  8. package/src/components/Button.vue +155 -0
  9. package/src/components/Card.vue +37 -0
  10. package/src/components/DatePicker.vue +252 -0
  11. package/src/components/Dialog.vue +216 -0
  12. package/src/components/Dropdown.vue +145 -0
  13. package/src/components/ErrorMessage.vue +24 -0
  14. package/src/components/FeatherIcon.vue +59 -0
  15. package/src/components/FileUploader.vue +220 -0
  16. package/src/components/GreenCheckIcon.vue +16 -0
  17. package/src/components/Input.vue +214 -0
  18. package/src/components/Link.vue +28 -0
  19. package/src/components/ListItem.vue +28 -0
  20. package/src/components/LoadingIndicator.vue +27 -0
  21. package/src/components/LoadingText.vue +21 -0
  22. package/src/components/Popover.vue +253 -0
  23. package/src/components/Resource.vue +21 -0
  24. package/src/components/TextEditor/FontColor.vue +108 -0
  25. package/src/components/TextEditor/InsertImage.vue +74 -0
  26. package/src/components/TextEditor/InsertLink.vue +67 -0
  27. package/src/components/TextEditor/InsertVideo.vue +94 -0
  28. package/src/components/TextEditor/MentionList.vue +95 -0
  29. package/src/components/TextEditor/Menu.vue +99 -0
  30. package/src/components/TextEditor/TextEditor.vue +275 -0
  31. package/src/components/TextEditor/TextEditorBubbleMenu.vue +69 -0
  32. package/src/components/TextEditor/TextEditorFixedMenu.vue +72 -0
  33. package/src/components/TextEditor/TextEditorFloatingMenu.vue +55 -0
  34. package/src/components/TextEditor/commands.js +272 -0
  35. package/src/components/TextEditor/icons/align-center.vue +14 -0
  36. package/src/components/TextEditor/icons/align-justify.vue +14 -0
  37. package/src/components/TextEditor/icons/align-left.vue +14 -0
  38. package/src/components/TextEditor/icons/align-right.vue +14 -0
  39. package/src/components/TextEditor/icons/arrow-go-back-line.vue +14 -0
  40. package/src/components/TextEditor/icons/arrow-go-forward-line.vue +14 -0
  41. package/src/components/TextEditor/icons/bold.vue +14 -0
  42. package/src/components/TextEditor/icons/code-view.vue +14 -0
  43. package/src/components/TextEditor/icons/double-quotes-r.vue +14 -0
  44. package/src/components/TextEditor/icons/font-color.vue +14 -0
  45. package/src/components/TextEditor/icons/format-clear.vue +14 -0
  46. package/src/components/TextEditor/icons/h-1.vue +14 -0
  47. package/src/components/TextEditor/icons/h-2.vue +14 -0
  48. package/src/components/TextEditor/icons/h-3.vue +14 -0
  49. package/src/components/TextEditor/icons/h-4.vue +14 -0
  50. package/src/components/TextEditor/icons/h-5.vue +14 -0
  51. package/src/components/TextEditor/icons/h-6.vue +14 -0
  52. package/src/components/TextEditor/icons/image-add-line.vue +14 -0
  53. package/src/components/TextEditor/icons/italic.vue +14 -0
  54. package/src/components/TextEditor/icons/link.vue +14 -0
  55. package/src/components/TextEditor/icons/list-ordered.vue +14 -0
  56. package/src/components/TextEditor/icons/list-unordered.vue +14 -0
  57. package/src/components/TextEditor/icons/readme.md +1 -0
  58. package/src/components/TextEditor/icons/separator.vue +14 -0
  59. package/src/components/TextEditor/icons/strikethrough.vue +14 -0
  60. package/src/components/TextEditor/icons/table-2.vue +14 -0
  61. package/src/components/TextEditor/icons/text.vue +11 -0
  62. package/src/components/TextEditor/icons/underline.vue +14 -0
  63. package/src/components/TextEditor/icons/video-add-line.vue +14 -0
  64. package/src/components/TextEditor/image-extension.js +152 -0
  65. package/src/components/TextEditor/index.js +6 -0
  66. package/src/components/TextEditor/mention.js +72 -0
  67. package/src/components/TextEditor/utils.js +11 -0
  68. package/src/components/TextEditor/video-extension.js +60 -0
  69. package/src/components/Toast.vue +83 -0
  70. package/src/components/Tooltip.vue +36 -0
  71. package/src/components/toast.js +98 -0
  72. package/src/directives/onOutsideClick.js +34 -0
  73. package/src/directives/visibility.js +24 -0
  74. package/src/index.js +56 -0
  75. package/src/resources/documentResource.js +194 -0
  76. package/src/resources/index.js +4 -0
  77. package/src/resources/listResource.js +312 -0
  78. package/src/resources/local.js +16 -0
  79. package/src/resources/plugin.js +105 -0
  80. package/src/resources/resources.js +215 -0
  81. package/src/style.css +15 -0
  82. package/src/utils/call.js +98 -0
  83. package/src/utils/config.js +9 -0
  84. package/src/utils/debounce.js +15 -0
  85. package/src/utils/file-to-base64.js +9 -0
  86. package/src/utils/markdown.js +29 -0
  87. package/src/utils/melonRequest.js +105 -0
  88. package/src/utils/pageMeta.js +52 -0
  89. package/src/utils/plugin.js +24 -0
  90. package/src/utils/request.js +49 -0
  91. package/src/utils/socketio.js +11 -0
  92. package/src/utils/tailwind.config.js +117 -0
  93. package/src/utils/vite-dev-server.js +14 -0
@@ -0,0 +1,215 @@
1
+ import { reactive } from 'vue'
2
+ import { debounce, request } from '../index'
3
+ import { getLocal, saveLocal } from './local'
4
+ import { getConfig } from '../utils/config'
5
+
6
+ let cached = {}
7
+
8
+ export function createResource(options, vm) {
9
+ let cacheKey = null
10
+ if (options.cache) {
11
+ cacheKey = getCacheKey(options.cache)
12
+ let cachedResource = cached[cacheKey]
13
+
14
+ if (cachedResource) {
15
+ if (cachedResource.auto) {
16
+ cachedResource.reload()
17
+ }
18
+ return cachedResource
19
+ }
20
+ }
21
+
22
+ if (typeof options == 'string') {
23
+ options = {
24
+ url: options,
25
+ auto: true,
26
+ }
27
+ }
28
+
29
+ let fetchFunction = options.debounce
30
+ ? debounce(fetch, options.debounce)
31
+ : fetch
32
+
33
+ let out = reactive({
34
+ method: options.method,
35
+ url: options.url,
36
+ data: options.initialData || null,
37
+ previousData: null,
38
+ loading: false,
39
+ fetched: false,
40
+ error: null,
41
+ promise: null,
42
+ auto: options.auto,
43
+ params: null,
44
+ fetch: fetchFunction,
45
+ reload: fetchFunction,
46
+ submit: fetchFunction,
47
+ reset,
48
+ update,
49
+ setData,
50
+ })
51
+
52
+ async function fetch(params, tempOptions = {}) {
53
+ let resourceFetcher =
54
+ options.resourceFetcher || getConfig('resourceFetcher') || request
55
+
56
+ if (params instanceof Event) {
57
+ params = null
58
+ }
59
+ params = params || out.params
60
+ if (options.makeParams) {
61
+ params = options.makeParams.call(vm, params)
62
+ }
63
+ out.params = params
64
+ out.previousData = out.data ? JSON.parse(JSON.stringify(out.data)) : null
65
+ out.loading = true
66
+ out.error = null
67
+
68
+ if (options.onFetch) {
69
+ options.onFetch.call(vm, out.params)
70
+ }
71
+
72
+ let beforeSubmitFunctions = [options.beforeSubmit, tempOptions.beforeSubmit]
73
+ for (let fn of beforeSubmitFunctions) {
74
+ if (fn) {
75
+ fn.call(vm, out.params)
76
+ }
77
+ }
78
+
79
+ let validateFunction = tempOptions.validate || options.validate
80
+ let errorFunctions = [options.onError, tempOptions.onError]
81
+ let successFunctions = [options.onSuccess, tempOptions.onSuccess]
82
+ let dataFunctions = [options.onData, tempOptions.onData]
83
+
84
+ if (validateFunction) {
85
+ let invalidMessage
86
+ try {
87
+ invalidMessage = await validateFunction.call(vm, out.params)
88
+ if (invalidMessage && typeof invalidMessage == 'string') {
89
+ let error = new Error(invalidMessage)
90
+ handleError(error, errorFunctions)
91
+ return
92
+ }
93
+ } catch (error) {
94
+ handleError(error, errorFunctions)
95
+ return
96
+ }
97
+ }
98
+
99
+ try {
100
+ out.promise = resourceFetcher({
101
+ ...options,
102
+ params: params || options.params,
103
+ })
104
+ let data = await out.promise
105
+ saveLocal(cacheKey, data)
106
+ out.data = transform(data)
107
+ out.fetched = true
108
+ for (let fn of successFunctions) {
109
+ if (fn) {
110
+ fn.call(vm, data)
111
+ }
112
+ }
113
+ for (let fn of dataFunctions) {
114
+ if (fn) {
115
+ fn.call(vm, data)
116
+ }
117
+ }
118
+ } catch (error) {
119
+ handleError(error, errorFunctions)
120
+ }
121
+ out.loading = false
122
+ return out.data
123
+ }
124
+
125
+ function update({ method, url, params, auto }) {
126
+ if (method && method !== options.method) {
127
+ out.method = method
128
+ }
129
+ if (url && url !== options.url) {
130
+ out.url = url
131
+ }
132
+ if (params && params !== options.params) {
133
+ out.params = params
134
+ }
135
+ if (auto !== undefined && auto !== out.auto) {
136
+ out.auto = auto
137
+ }
138
+ }
139
+
140
+ function reset() {
141
+ out.data = options.initialData || null
142
+ out.previousData = null
143
+ out.loading = false
144
+ out.fetched = false
145
+ out.error = null
146
+ out.params = null
147
+ out.auto = options.auto
148
+ }
149
+
150
+ function handleError(error, errorFunctions) {
151
+ out.loading = false
152
+ if (out.previousData) {
153
+ out.data = out.previousData
154
+ }
155
+ out.error = error
156
+ for (let fn of errorFunctions) {
157
+ if (fn) {
158
+ fn.call(vm, error)
159
+ }
160
+ }
161
+ throw error
162
+ }
163
+
164
+ // usage:
165
+ // setData(newData) or
166
+ // setData(data => data.filter(d => !d.deleted))
167
+ function setData(data) {
168
+ if (typeof data === 'function') {
169
+ data = data.call(vm, out.data)
170
+ }
171
+ out.data = transform(data)
172
+ }
173
+
174
+ function transform(data) {
175
+ if (options.transform) {
176
+ let returnValue = options.transform.call(vm, data)
177
+ if (returnValue != null) {
178
+ return returnValue
179
+ }
180
+ }
181
+ return data
182
+ }
183
+
184
+ if (cacheKey && !cached[cacheKey]) {
185
+ cached[cacheKey] = out
186
+ // offline
187
+ getLocal(cacheKey).then((data) => {
188
+ if ((out.loading || !out.fetched) && data) {
189
+ setData(data)
190
+ options.onData?.call(vm, data)
191
+ }
192
+ })
193
+ }
194
+
195
+ if (options.auto) {
196
+ out.fetch()
197
+ }
198
+
199
+ return out
200
+ }
201
+
202
+ export function getCacheKey(cacheKey) {
203
+ if (!cacheKey) {
204
+ return null
205
+ }
206
+ if (typeof cacheKey === 'string') {
207
+ cacheKey = [cacheKey]
208
+ }
209
+ return JSON.stringify(cacheKey)
210
+ }
211
+
212
+ export function getCachedResource(cacheKey) {
213
+ cacheKey = getCacheKey(cacheKey)
214
+ return cached[cacheKey] || null
215
+ }
package/src/style.css ADDED
@@ -0,0 +1,15 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer components {
6
+ .form-input,
7
+ .form-textarea,
8
+ .form-select {
9
+ @apply rounded-md border-0 bg-gray-100 py-1 text-base leading-5 placeholder-gray-700 focus:bg-gray-200 focus:shadow-none focus:ring-0;
10
+ }
11
+
12
+ .form-checkbox {
13
+ @apply rounded-md bg-gray-100 text-blue-500 focus:ring-0 focus-visible:ring-1;
14
+ }
15
+ }
@@ -0,0 +1,98 @@
1
+ export default async function call(method, args, options = {}) {
2
+ if (!args) {
3
+ args = {}
4
+ }
5
+
6
+ let headers = Object.assign(
7
+ {
8
+ Accept: 'application/json',
9
+ 'Content-Type': 'application/json; charset=utf-8',
10
+ 'X-Melon-Site-Name': window.location.hostname,
11
+ },
12
+ options.headers || {}
13
+ )
14
+
15
+ if (window.csrf_token && window.csrf_token !== '{{ csrf_token }}') {
16
+ headers['X-Melon-CSRF-Token'] = window.csrf_token
17
+ }
18
+
19
+ let path = method.startsWith('/') ? method : `/api/method/${method}`
20
+ const res = await fetch(path, {
21
+ method: 'POST',
22
+ headers,
23
+ body: JSON.stringify(args),
24
+ })
25
+
26
+ if (res.ok) {
27
+ const data = await res.json()
28
+ if (data.docs || method === 'login') {
29
+ return data
30
+ }
31
+ if (data.exc) {
32
+ try {
33
+ console.groupCollapsed(method)
34
+ console.log(`method: ${method}`)
35
+ console.log(`params:`, args)
36
+ let warning = JSON.parse(data.exc)
37
+ for (let text of warning) {
38
+ console.log(text)
39
+ }
40
+ console.groupEnd()
41
+ } catch (e) {
42
+ console.warn('Error printing debug messages', e)
43
+ }
44
+ }
45
+ return data.message
46
+ } else {
47
+ let response = await res.text()
48
+ let error, exception
49
+ try {
50
+ error = JSON.parse(response)
51
+ // eslint-disable-next-line no-empty
52
+ } catch (e) {}
53
+ let errorParts = [
54
+ [method, error.exc_type, error._error_message].filter(Boolean).join(' '),
55
+ ]
56
+ if (error.exc) {
57
+ exception = error.exc
58
+ try {
59
+ exception = JSON.parse(exception)[0]
60
+ console.log(exception)
61
+ // eslint-disable-next-line no-empty
62
+ } catch (e) {}
63
+ }
64
+ let e = new Error(errorParts.join('\n'))
65
+ e.exc_type = error.exc_type
66
+ e.exc = exception
67
+ e.status = res.status
68
+ e.messages = error._server_messages
69
+ ? JSON.parse(error._server_messages)
70
+ : []
71
+ e.messages = e.messages.concat(error.message)
72
+ e.messages = e.messages.map((m) => {
73
+ try {
74
+ return JSON.parse(m).message
75
+ } catch (error) {
76
+ return m
77
+ }
78
+ })
79
+ e.messages = e.messages.filter(Boolean)
80
+ if (!e.messages.length) {
81
+ e.messages = error._error_message
82
+ ? [error._error_message]
83
+ : ['Internal Server Error']
84
+ }
85
+
86
+ if (options.onError) {
87
+ options.onError({ response: res, status: res.status, error: e })
88
+ }
89
+
90
+ throw e
91
+ }
92
+ }
93
+
94
+ export function createCall(options) {
95
+ return function customCall(method, args) {
96
+ return call(method, args, options)
97
+ }
98
+ }
@@ -0,0 +1,9 @@
1
+ let config = {}
2
+
3
+ export function setConfig(key, value) {
4
+ config[key] = value
5
+ }
6
+
7
+ export function getConfig(key) {
8
+ return config[key] || null
9
+ }
@@ -0,0 +1,15 @@
1
+ export default function debounce(func, wait, immediate) {
2
+ var timeout
3
+ return function () {
4
+ var context = this,
5
+ args = arguments
6
+ var later = function () {
7
+ timeout = null
8
+ if (!immediate) func.apply(context, args)
9
+ }
10
+ var callNow = immediate && !timeout
11
+ clearTimeout(timeout)
12
+ timeout = setTimeout(later, wait)
13
+ if (callNow) func.apply(context, args)
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ export default (file) => {
2
+ return new Promise((resolve) => {
3
+ let reader = new FileReader()
4
+ reader.onloadend = () => {
5
+ resolve(reader.result)
6
+ }
7
+ reader.readAsDataURL(file)
8
+ })
9
+ }
@@ -0,0 +1,29 @@
1
+ import showdown from 'showdown'
2
+
3
+ export function markdownToHTML(text) {
4
+ const converter = new showdown.Converter()
5
+ return converter.makeHtml(text)
6
+ }
7
+
8
+ export function htmlToMarkdown(text) {
9
+ const converter = new showdown.Converter()
10
+ return converter.makeMarkdown(text)
11
+ }
12
+
13
+ export function detectMarkdown(text) {
14
+ const lines = text.split('\n')
15
+ const markdown = lines.filter(
16
+ (line) =>
17
+ line.startsWith('![') ||
18
+ line.startsWith('#') ||
19
+ line.startsWith('> ') ||
20
+ line.startsWith('*') ||
21
+ line.startsWith('- ') ||
22
+ line.startsWith('1. ') ||
23
+ line.startsWith('```') ||
24
+ line.startsWith('`') ||
25
+ line.startsWith('[') ||
26
+ line.startsWith('---')
27
+ )
28
+ return markdown.length > 0
29
+ }
@@ -0,0 +1,105 @@
1
+ import { request } from './request'
2
+
3
+ export function melonRequest(options) {
4
+ return request({
5
+ ...options,
6
+ transformRequest: (options = {}) => {
7
+ if (!options.url) {
8
+ throw new Error('[melonRequest] options.url is required')
9
+ }
10
+ let headers = Object.assign(
11
+ {
12
+ Accept: 'application/json',
13
+ 'Content-Type': 'application/json; charset=utf-8',
14
+ 'X-Melon-Site-Name': window.location.hostname,
15
+ },
16
+ options.headers || {}
17
+ )
18
+ if (window.csrf_token && window.csrf_token !== '{{ csrf_token }}') {
19
+ headers['X-Melon-CSRF-Token'] = window.csrf_token
20
+ }
21
+ if (!options.url.startsWith('/') && !options.url.startsWith('http')) {
22
+ options.url = '/api/method/' + options.url
23
+ }
24
+ return {
25
+ ...options,
26
+ method: options.method || 'POST',
27
+ headers,
28
+ }
29
+ },
30
+ transformResponse: async (response, options) => {
31
+ let url = options.url
32
+ if (response.ok) {
33
+ const data = await response.json()
34
+ if (data.docs || url === 'login') {
35
+ return data
36
+ }
37
+ if (data.exc) {
38
+ try {
39
+ console.groupCollapsed(url)
40
+ console.log(options)
41
+ let warning = JSON.parse(data.exc)
42
+ for (let text of warning) {
43
+ console.log(text)
44
+ }
45
+ console.groupEnd()
46
+ } catch (e) {
47
+ console.warn('Error printing debug messages', e)
48
+ }
49
+ }
50
+ return data.message
51
+ } else {
52
+ let errorResponse = await response.text()
53
+ let error, exception
54
+ try {
55
+ error = JSON.parse(errorResponse)
56
+ // eslint-disable-next-line no-empty
57
+ } catch (e) {}
58
+ let errorParts = [
59
+ [options.url, error.exc_type, error._error_message]
60
+ .filter(Boolean)
61
+ .join(' '),
62
+ ]
63
+ if (error.exc) {
64
+ exception = error.exc
65
+ try {
66
+ exception = JSON.parse(exception)[0]
67
+ console.log(exception)
68
+ // eslint-disable-next-line no-empty
69
+ } catch (e) {}
70
+ }
71
+ let e = new Error(errorParts.join('\n'))
72
+ e.exc_type = error.exc_type
73
+ e.exc = exception
74
+ e.status = errorResponse.status
75
+ e.messages = error._server_messages
76
+ ? JSON.parse(error._server_messages)
77
+ : []
78
+ e.messages = e.messages.concat(error.message)
79
+ e.messages = e.messages.map((m) => {
80
+ try {
81
+ return JSON.parse(m).message
82
+ } catch (error) {
83
+ return m
84
+ }
85
+ })
86
+ e.messages = e.messages.filter(Boolean)
87
+ if (!e.messages.length) {
88
+ e.messages = error._error_message
89
+ ? [error._error_message]
90
+ : ['Internal Server Error']
91
+ }
92
+
93
+ if (options.onError) {
94
+ options.onError({
95
+ response: errorResponse,
96
+ status: errorResponse.status,
97
+ error: e,
98
+ })
99
+ }
100
+
101
+ throw e
102
+ }
103
+ },
104
+ })
105
+ }
@@ -0,0 +1,52 @@
1
+ import { watch } from 'vue'
2
+
3
+ export default {
4
+ install(app) {
5
+ app.mixin(createMixin())
6
+ },
7
+ }
8
+
9
+ function createMixin() {
10
+ let faviconRef = document.querySelector('link[rel="icon"]')
11
+ let defaultFavIcon = faviconRef.href
12
+
13
+ return {
14
+ created() {
15
+ if (this.$options.pageMeta) {
16
+ watch(
17
+ () => {
18
+ try {
19
+ return this.$options.pageMeta.call(this)
20
+ } catch (error) {
21
+ let debugInfo = `${this.$options.name} (${
22
+ this.$options.__file || ''
23
+ })`
24
+ if (process.env.NODE_ENV === 'development') {
25
+ console.warn('Failed to parse pageMeta in', debugInfo)
26
+ }
27
+ return null
28
+ }
29
+ },
30
+ (pageMeta) => {
31
+ if (!pageMeta) return
32
+ if (pageMeta.title) {
33
+ document.title = pageMeta.title
34
+ }
35
+ if (pageMeta.emoji) {
36
+ let href = `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${pageMeta.emoji}</text></svg>`
37
+ faviconRef.href = href
38
+ } else if (pageMeta.icon) {
39
+ faviconRef.href = pageMeta.icon
40
+ } else {
41
+ faviconRef.href = defaultFavIcon
42
+ }
43
+ },
44
+ {
45
+ immediate: true,
46
+ deep: true,
47
+ }
48
+ )
49
+ }
50
+ },
51
+ }
52
+ }
@@ -0,0 +1,24 @@
1
+ import resourcesPlugin from '../resources/plugin'
2
+ import call from './call'
3
+ import initSocket from './socketio'
4
+
5
+ let defaultOptions = {
6
+ resources: true,
7
+ call: true,
8
+ socketio: true,
9
+ }
10
+
11
+ export default {
12
+ install(app, options = {}) {
13
+ options = Object.assign({}, defaultOptions, options)
14
+ options.resources && app.use(resourcesPlugin, options.resources)
15
+
16
+ if (options.call) {
17
+ let callFunction = typeof options.call == 'function' ? options.call : call
18
+ app.config.globalProperties.$call = callFunction
19
+ }
20
+ if (options.socketio) {
21
+ app.config.globalProperties.$socket = initSocket(options.socketio)
22
+ }
23
+ },
24
+ }
@@ -0,0 +1,49 @@
1
+ export function request(_options) {
2
+ let options = Object.assign({}, _options)
3
+ if (!options.url) {
4
+ throw new Error('[request] options.url is required')
5
+ }
6
+ if (options.transformRequest) {
7
+ options = options.transformRequest(_options)
8
+ }
9
+ if (!options.responseType) {
10
+ options.responseType = 'json'
11
+ }
12
+ if (!options.method) {
13
+ options.method = 'GET'
14
+ }
15
+
16
+ let url = options.url
17
+ let body
18
+ if (options.params) {
19
+ if (options.method === 'GET') {
20
+ let params = new URLSearchParams()
21
+ for (let key in options.params) {
22
+ params.append(key, options.params[key])
23
+ }
24
+ url = options.url + '?' + params.toString()
25
+ } else {
26
+ body = JSON.stringify(options.params)
27
+ }
28
+ }
29
+
30
+ return fetch(url, {
31
+ method: options.method || 'GET',
32
+ headers: options.headers,
33
+ body,
34
+ }).then((response) => {
35
+ if (options.transformResponse) {
36
+ return options.transformResponse(response, options)
37
+ }
38
+ if (response.status >= 200 && response.status < 300) {
39
+ if (options.responseType === 'json') {
40
+ return response.json()
41
+ }
42
+ return response
43
+ } else {
44
+ let error = new Error(response.statusText)
45
+ error.response = response
46
+ throw error
47
+ }
48
+ })
49
+ }
@@ -0,0 +1,11 @@
1
+ import { io } from 'socket.io-client'
2
+
3
+ export default function initSocket(options = {}) {
4
+ let host = window.location.hostname
5
+ let socketio_port = options.port || 9000
6
+ let port = window.location.port ? `:${socketio_port}` : ''
7
+ let protocol = port ? 'http' : 'https'
8
+ let url = `${protocol}://${host}${port}`
9
+ let socket = io(url, { withCredentials: true })
10
+ return socket
11
+ }