@operato/font 1.0.0-beta.14 → 1.0.0-beta.17
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.
- package/CHANGELOG.md +25 -0
- package/package.json +44 -11
- package/src/font-creation-card.js +73 -114
- package/src/font-selector.js +78 -256
- package/src/graphql-client.js +32 -22
- package/src/index.js +6 -3
- package/src/ox-file-selector.js +138 -0
- package/src/ox-font-selector.js +29 -33
- package/src/ox-property-editor-font-selector.js +6 -14
- package/src/redux-font-actions.js +20 -0
- package/src/redux-font-reducers.js +80 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.0.0-beta.17](https://github.com/hatiolab/operato/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2022-05-25)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* reform font ui ([fcfa5b0](https://github.com/hatiolab/operato/commit/fcfa5b06222579e45a79fa94e8823178cfdacca2))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## [1.0.0-beta.16](https://github.com/hatiolab/operato/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2022-05-23)
|
|
16
|
+
|
|
17
|
+
**Note:** Version bump only for package @operato/font
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## [1.0.0-beta.15](https://github.com/hatiolab/operato/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2022-05-20)
|
|
24
|
+
|
|
25
|
+
**Note:** Version bump only for package @operato/font
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
6
31
|
## [1.0.0-beta.14](https://github.com/hatiolab/operato/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2022-05-19)
|
|
7
32
|
|
|
8
33
|
**Note:** Version bump only for package @operato/font
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "User interface to select font and create font.",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "heartyoh",
|
|
6
|
-
"version": "1.0.0-beta.
|
|
6
|
+
"version": "1.0.0-beta.17",
|
|
7
7
|
"main": "src/index.js",
|
|
8
8
|
"module": "src/index.js",
|
|
9
9
|
"exports": {
|
|
@@ -24,15 +24,48 @@
|
|
|
24
24
|
"scripts": {},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@material/mwc-icon": "^0.25.3",
|
|
27
|
-
"@operato/attachment": "^1.0.0-beta.
|
|
28
|
-
"@operato/headroom": "^1.0.0-beta.
|
|
29
|
-
"@operato/i18n": "^1.0.0-beta.
|
|
30
|
-
"@operato/layout": "^1.0.0-beta.
|
|
31
|
-
"@operato/property-editor": "^1.0.0-beta.
|
|
32
|
-
"@operato/pull-to-refresh": "^1.0.0-beta.
|
|
33
|
-
"@operato/shell": "^1.0.0-beta.
|
|
34
|
-
"@operato/utils": "^1.0.0-beta.
|
|
35
|
-
"uuid": "^3.4.0"
|
|
27
|
+
"@operato/attachment": "^1.0.0-beta.17",
|
|
28
|
+
"@operato/headroom": "^1.0.0-beta.17",
|
|
29
|
+
"@operato/i18n": "^1.0.0-beta.17",
|
|
30
|
+
"@operato/layout": "^1.0.0-beta.17",
|
|
31
|
+
"@operato/property-editor": "^1.0.0-beta.17",
|
|
32
|
+
"@operato/pull-to-refresh": "^1.0.0-beta.17",
|
|
33
|
+
"@operato/shell": "^1.0.0-beta.17",
|
|
34
|
+
"@operato/utils": "^1.0.0-beta.17",
|
|
35
|
+
"uuid": "^3.4.0",
|
|
36
|
+
"webfontloader": "^1.6.28"
|
|
36
37
|
},
|
|
37
|
-
"
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@custom-elements-manifest/analyzer": "^0.4.17",
|
|
40
|
+
"@hatiolab/prettier-config": "^1.0.0",
|
|
41
|
+
"@open-wc/eslint-config": "^4.3.0",
|
|
42
|
+
"@open-wc/testing": "^3.0.4",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
44
|
+
"@typescript-eslint/parser": "^4.33.0",
|
|
45
|
+
"@web/dev-server": "^0.1.29",
|
|
46
|
+
"@web/dev-server-storybook": "^0.5.0",
|
|
47
|
+
"@web/test-runner": "next",
|
|
48
|
+
"concurrently": "^5.3.0",
|
|
49
|
+
"eslint": "^7.32.0",
|
|
50
|
+
"eslint-config-prettier": "^8.3.0",
|
|
51
|
+
"husky": "^7.0.2",
|
|
52
|
+
"json5": "^2.2.0",
|
|
53
|
+
"lint-staged": "^10.5.4",
|
|
54
|
+
"prettier": "^2.4.1",
|
|
55
|
+
"tslib": "^2.3.1",
|
|
56
|
+
"typescript": "^4.5.2"
|
|
57
|
+
},
|
|
58
|
+
"prettier": "@hatiolab/prettier-config",
|
|
59
|
+
"husky": {
|
|
60
|
+
"hooks": {
|
|
61
|
+
"pre-commit": "lint-staged"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"lint-staged": {
|
|
65
|
+
"*.ts": [
|
|
66
|
+
"eslint --fix",
|
|
67
|
+
"prettier --write"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"gitHead": "4894bb50eb5bf25722360a7786fb142f2dcf9b97"
|
|
38
71
|
}
|
|
@@ -1,35 +1,34 @@
|
|
|
1
|
-
import
|
|
1
|
+
import './ox-file-selector'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { i18next, localize } from "@operato/i18n";
|
|
3
|
+
import { css, html, LitElement } from 'lit'
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { i18next, localize } from '@operato/i18n'
|
|
7
6
|
|
|
8
7
|
export class FontCreationCard extends localize(i18next)(LitElement) {
|
|
9
8
|
static get properties() {
|
|
10
9
|
return {
|
|
11
10
|
provider: {
|
|
12
|
-
type: String
|
|
11
|
+
type: String
|
|
13
12
|
},
|
|
14
13
|
googleFonts: {
|
|
15
|
-
type: Array
|
|
14
|
+
type: Array
|
|
16
15
|
},
|
|
17
|
-
|
|
18
|
-
type: Array
|
|
19
|
-
}
|
|
20
|
-
}
|
|
16
|
+
files: {
|
|
17
|
+
type: Array
|
|
18
|
+
}
|
|
19
|
+
}
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
constructor() {
|
|
24
|
-
super()
|
|
25
|
-
this.provider =
|
|
23
|
+
super()
|
|
24
|
+
this.provider = 'google'
|
|
26
25
|
this.providers = [
|
|
27
|
-
{ value:
|
|
26
|
+
{ value: 'google', display: 'Google' },
|
|
28
27
|
// TODO 구글 외 폰트 서비스 구현
|
|
29
28
|
// { value: 'typekit', display: 'Typekit' },
|
|
30
|
-
{ value:
|
|
31
|
-
]
|
|
32
|
-
this.googleFonts = []
|
|
29
|
+
{ value: 'custom', display: 'Custom' }
|
|
30
|
+
]
|
|
31
|
+
this.googleFonts = []
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
static get styles() {
|
|
@@ -48,12 +47,6 @@ export class FontCreationCard extends localize(i18next)(LitElement) {
|
|
|
48
47
|
transition: all 0.5s ease-in-out;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
:host(.candrop) [front],
|
|
52
|
-
:host(.candrop) [back] {
|
|
53
|
-
border-width: 2px;
|
|
54
|
-
background-color: #fffde9;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
50
|
:host(.flipped) {
|
|
58
51
|
-webkit-transform: var(--card-list-flip-transform);
|
|
59
52
|
transform: var(--card-list-flip-transform);
|
|
@@ -141,7 +134,7 @@ export class FontCreationCard extends localize(i18next)(LitElement) {
|
|
|
141
134
|
width: -moz-available;
|
|
142
135
|
}
|
|
143
136
|
|
|
144
|
-
file-selector {
|
|
137
|
+
ox-file-selector {
|
|
145
138
|
grid-column: span 6;
|
|
146
139
|
font: var(--card-list-create-input-font);
|
|
147
140
|
border: none;
|
|
@@ -149,7 +142,7 @@ export class FontCreationCard extends localize(i18next)(LitElement) {
|
|
|
149
142
|
padding: 0;
|
|
150
143
|
}
|
|
151
144
|
|
|
152
|
-
[back] input[type=
|
|
145
|
+
[back] input[type='submit'] {
|
|
153
146
|
background-color: var(--button-background-color) !important;
|
|
154
147
|
font: var(--button-font);
|
|
155
148
|
color: var(--button-color) !important;
|
|
@@ -162,150 +155,116 @@ export class FontCreationCard extends localize(i18next)(LitElement) {
|
|
|
162
155
|
.hidden {
|
|
163
156
|
display: none !important;
|
|
164
157
|
}
|
|
165
|
-
|
|
166
|
-
]
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async firstUpdated() {
|
|
170
|
-
FileDropHelper.set(this);
|
|
158
|
+
`
|
|
159
|
+
]
|
|
171
160
|
}
|
|
172
161
|
|
|
173
162
|
render() {
|
|
174
|
-
let isProviderGoogle =
|
|
175
|
-
|
|
176
|
-
let isFileAttached = this._files.length > 0 ? true : false;
|
|
163
|
+
let isProviderGoogle = this.provider == 'google' && this.googleFonts.length > 0
|
|
164
|
+
let isFileAttached = this.files.length > 0 ? true : false
|
|
177
165
|
return html`
|
|
178
|
-
<div @click=${
|
|
179
|
-
<mwc-icon>add_circle_outline</mwc-icon>create font
|
|
180
|
-
</div>
|
|
166
|
+
<div @click=${e => this.onClickFlip(e)} front><mwc-icon>add_circle_outline</mwc-icon>create font</div>
|
|
181
167
|
|
|
182
|
-
<div @click=${
|
|
183
|
-
<form @submit=${
|
|
168
|
+
<div @click=${e => this.onClickFlip(e)} back>
|
|
169
|
+
<form @submit=${e => this.onClickSubmit(e)}>
|
|
184
170
|
<div class="props">
|
|
185
|
-
<label>${i18next.t(
|
|
171
|
+
<label>${i18next.t('label.provider')}</label>
|
|
186
172
|
<select
|
|
187
173
|
name="provider"
|
|
188
|
-
@change=${
|
|
189
|
-
this.provider = e.target.value
|
|
190
|
-
if (e.target.value ===
|
|
191
|
-
fetch(`/all-google-fonts`).then(async
|
|
192
|
-
if (response.ok) this.googleFonts = await response.json()
|
|
174
|
+
@change=${e => {
|
|
175
|
+
this.provider = e.target.value
|
|
176
|
+
if (e.target.value === 'google') {
|
|
177
|
+
fetch(`/all-google-fonts`).then(async response => {
|
|
178
|
+
if (response.ok) this.googleFonts = await response.json()
|
|
193
179
|
else {
|
|
194
180
|
console.warn(
|
|
195
181
|
`(${response.url}) ${response.status} ${response.statusText}. Could not load Google fonts.`
|
|
196
|
-
)
|
|
182
|
+
)
|
|
197
183
|
}
|
|
198
|
-
})
|
|
184
|
+
})
|
|
199
185
|
}
|
|
200
186
|
}}
|
|
201
187
|
>
|
|
202
188
|
${this.providers.map(
|
|
203
|
-
|
|
204
|
-
html`
|
|
205
|
-
<option
|
|
206
|
-
value=${p.value}
|
|
207
|
-
?selected=${this.provider == p.value}
|
|
208
|
-
>
|
|
209
|
-
${p.display}
|
|
210
|
-
</option>
|
|
211
|
-
`
|
|
189
|
+
p => html` <option value=${p.value} ?selected=${this.provider == p.value}>${p.display}</option> `
|
|
212
190
|
)}
|
|
213
191
|
</select>
|
|
214
192
|
|
|
215
|
-
<label>${i18next.t(
|
|
216
|
-
<input
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
/>
|
|
221
|
-
<select
|
|
222
|
-
name="${isProviderGoogle ? "name" : ""}"
|
|
223
|
-
?hidden=${!isProviderGoogle}
|
|
224
|
-
>
|
|
225
|
-
${isProviderGoogle &&
|
|
226
|
-
this.googleFonts.map(
|
|
227
|
-
(f) => html` <option value=${f}>${f}</option> `
|
|
228
|
-
)}
|
|
193
|
+
<label>${i18next.t('label.name')}</label>
|
|
194
|
+
<input type="text" name="${isProviderGoogle ? '' : 'name'}" ?hidden=${isProviderGoogle} />
|
|
195
|
+
<select name="${isProviderGoogle ? 'name' : ''}" ?hidden=${!isProviderGoogle}>
|
|
196
|
+
<option value=""> </option>
|
|
197
|
+
${isProviderGoogle && this.googleFonts.map(f => html` <option value=${f}>${f}</option> `)}
|
|
229
198
|
</select>
|
|
230
199
|
|
|
231
|
-
<label ?hidden=${this.provider !=
|
|
232
|
-
>${i18next.t("label.uri")}</label
|
|
233
|
-
>
|
|
200
|
+
<label ?hidden=${this.provider != 'custom'}>${i18next.t('label.uri')}</label>
|
|
234
201
|
<input
|
|
235
|
-
?hidden=${this.provider !=
|
|
202
|
+
?hidden=${this.provider != 'custom'}
|
|
236
203
|
?disabled=${isFileAttached}
|
|
237
|
-
.value=${isFileAttached ? this.
|
|
204
|
+
.value=${isFileAttached ? this.files[0].name : ''}
|
|
238
205
|
type="text"
|
|
239
206
|
name="uri"
|
|
240
207
|
/>
|
|
241
208
|
<!-- display when attachment module is imported -->
|
|
242
|
-
<label ?hidden=${this.provider !=
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<file-selector
|
|
246
|
-
class="${this.provider != "custom" ? "hidden" : ""}"
|
|
209
|
+
<label ?hidden=${this.provider != 'custom'}>${i18next.t('label.file')}</label>
|
|
210
|
+
<ox-file-selector
|
|
211
|
+
class="${this.provider != 'custom' ? 'hidden' : ''}"
|
|
247
212
|
name="file"
|
|
248
|
-
label="${i18next.t(
|
|
213
|
+
label="${i18next.t('label.select file')}"
|
|
249
214
|
accept=".ttf,.otf,.woff,.woff2,.eot,.svg,.svgz"
|
|
250
215
|
multiple
|
|
251
|
-
@file-change=${
|
|
252
|
-
this.
|
|
216
|
+
@file-change=${e => {
|
|
217
|
+
this.files = Array.from(e.detail.files)
|
|
253
218
|
}}
|
|
254
|
-
></file-selector>
|
|
219
|
+
></ox-file-selector>
|
|
255
220
|
<!------------------------------------------------>
|
|
256
221
|
|
|
257
|
-
<label for="checkbox-active" @click=${
|
|
258
|
-
${i18next.t("label.active")}
|
|
259
|
-
</label>
|
|
222
|
+
<label for="checkbox-active" @click=${e => e.stopPropagation()}> ${i18next.t('label.active')} </label>
|
|
260
223
|
<input id="checkbox-active" type="checkbox" name="active" checked />
|
|
261
224
|
</div>
|
|
262
225
|
<div></div>
|
|
263
|
-
<input type="submit" value=${i18next.t(
|
|
226
|
+
<input type="submit" value=${i18next.t('button.create')} />
|
|
264
227
|
</form>
|
|
265
228
|
</div>
|
|
266
|
-
|
|
229
|
+
`
|
|
267
230
|
}
|
|
268
231
|
|
|
269
232
|
onClickFlip(e) {
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
)
|
|
274
|
-
) {
|
|
275
|
-
if (e.currentTarget.hasAttribute("front")) this.reset(); // 입력 폼으로 뒤집기 전에 한 번 리셋
|
|
276
|
-
this.classList.toggle("flipped");
|
|
233
|
+
if (!['INPUT', 'SELECT', 'OPTION'].find(tagName => tagName === e.target.tagName)) {
|
|
234
|
+
if (e.currentTarget.hasAttribute('front')) this.reset() // 입력 폼으로 뒤집기 전에 한 번 리셋
|
|
235
|
+
this.classList.toggle('flipped')
|
|
277
236
|
}
|
|
278
237
|
}
|
|
279
238
|
|
|
280
239
|
async onClickSubmit(e) {
|
|
281
|
-
e.preventDefault()
|
|
282
|
-
e.stopPropagation()
|
|
283
|
-
|
|
284
|
-
var form = e.target
|
|
285
|
-
|
|
286
|
-
var detail = {}
|
|
287
|
-
detail.name = form.elements[
|
|
288
|
-
detail.provider = form.elements[
|
|
289
|
-
detail.active = form.elements[
|
|
290
|
-
if (this.provider ===
|
|
291
|
-
detail.uri = form.elements[
|
|
292
|
-
if (this.
|
|
293
|
-
detail.
|
|
240
|
+
e.preventDefault()
|
|
241
|
+
e.stopPropagation()
|
|
242
|
+
|
|
243
|
+
var form = e.target
|
|
244
|
+
|
|
245
|
+
var detail = {}
|
|
246
|
+
detail.name = form.elements['name'].value
|
|
247
|
+
detail.provider = form.elements['provider'].value
|
|
248
|
+
detail.active = form.elements['active'].checked
|
|
249
|
+
if (this.provider === 'custom') {
|
|
250
|
+
detail.uri = form.elements['uri'].value
|
|
251
|
+
if (this.files?.length > 0) {
|
|
252
|
+
detail.files = this.files
|
|
294
253
|
}
|
|
295
254
|
}
|
|
296
255
|
|
|
297
|
-
this.dispatchEvent(new CustomEvent(
|
|
256
|
+
this.dispatchEvent(new CustomEvent('create-font', { detail }))
|
|
298
257
|
}
|
|
299
258
|
|
|
300
259
|
reset() {
|
|
301
|
-
var form = this.shadowRoot.querySelector(
|
|
260
|
+
var form = this.shadowRoot.querySelector('form')
|
|
302
261
|
if (form) {
|
|
303
|
-
form.reset()
|
|
262
|
+
form.reset()
|
|
304
263
|
}
|
|
305
264
|
|
|
306
|
-
this.
|
|
307
|
-
this.classList.remove(
|
|
265
|
+
this.files = []
|
|
266
|
+
this.classList.remove('flipped')
|
|
308
267
|
}
|
|
309
268
|
}
|
|
310
269
|
|
|
311
|
-
customElements.define(
|
|
270
|
+
customElements.define('font-creation-card', FontCreationCard)
|
package/src/font-selector.js
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import gql from "graphql-tag";
|
|
17
|
-
import { pulltorefresh } from "@operato/pull-to-refresh";
|
|
18
|
-
import { store } from "@operato/shell";
|
|
19
|
-
import uuid from "uuid/v4";
|
|
20
|
-
|
|
21
|
-
export class FontSelector extends localize(i18next)(
|
|
22
|
-
connect(store)(LitElement)
|
|
23
|
-
) {
|
|
1
|
+
import './font-creation-card'
|
|
2
|
+
|
|
3
|
+
import { css, html, LitElement } from 'lit'
|
|
4
|
+
import { connect } from 'pwa-helpers/connect-mixin.js'
|
|
5
|
+
|
|
6
|
+
import Headroom from '@operato/headroom'
|
|
7
|
+
import { i18next, localize } from '@operato/i18n'
|
|
8
|
+
import { pulltorefresh } from '@operato/pull-to-refresh'
|
|
9
|
+
import { store } from '@operato/shell'
|
|
10
|
+
import { HeadroomStyles, ScrollbarStyles } from '@operato/styles'
|
|
11
|
+
|
|
12
|
+
import { createFont, deleteFont, updateFont } from './graphql-client'
|
|
13
|
+
import { actionUpdateFontList } from './redux-font-actions'
|
|
14
|
+
|
|
15
|
+
export class FontSelector extends localize(i18next)(connect(store)(LitElement)) {
|
|
24
16
|
static get styles() {
|
|
25
17
|
return [
|
|
26
18
|
ScrollbarStyles,
|
|
@@ -35,11 +27,6 @@ export class FontSelector extends localize(i18next)(
|
|
|
35
27
|
position: relative;
|
|
36
28
|
}
|
|
37
29
|
|
|
38
|
-
:host(.candrop) {
|
|
39
|
-
background: orange;
|
|
40
|
-
cursor: pointer;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
30
|
#main {
|
|
44
31
|
overflow: auto;
|
|
45
32
|
padding: var(--popup-content-padding);
|
|
@@ -143,8 +130,8 @@ export class FontSelector extends localize(i18next)(
|
|
|
143
130
|
text-transform: capitalize;
|
|
144
131
|
float: right;
|
|
145
132
|
}
|
|
146
|
-
|
|
147
|
-
]
|
|
133
|
+
`
|
|
134
|
+
]
|
|
148
135
|
}
|
|
149
136
|
|
|
150
137
|
static get properties() {
|
|
@@ -152,43 +139,35 @@ export class FontSelector extends localize(i18next)(
|
|
|
152
139
|
fonts: Array,
|
|
153
140
|
_page: Number,
|
|
154
141
|
_total: Number,
|
|
155
|
-
creatable: Boolean
|
|
156
|
-
}
|
|
142
|
+
creatable: Boolean
|
|
143
|
+
}
|
|
157
144
|
}
|
|
158
145
|
|
|
159
146
|
render() {
|
|
160
|
-
var fonts = this.fonts || []
|
|
147
|
+
var fonts = this.fonts || []
|
|
161
148
|
|
|
162
149
|
return html`
|
|
163
150
|
<div id="filter">
|
|
164
151
|
<select
|
|
165
|
-
@change=${
|
|
166
|
-
this.provider = e.currentTarget.value
|
|
167
|
-
this.requestUpdate()
|
|
152
|
+
@change=${e => {
|
|
153
|
+
this.provider = e.currentTarget.value
|
|
154
|
+
this.requestUpdate()
|
|
168
155
|
}}
|
|
169
156
|
>
|
|
170
|
-
<option value="">
|
|
171
|
-
|
|
172
|
-
</option>
|
|
173
|
-
${["google", "custom"].map(
|
|
174
|
-
(provider) => html` <option value=${provider}>${provider}</option> `
|
|
175
|
-
)}
|
|
157
|
+
<option value="">--${i18next.t('text.please choose a provider')}--</option>
|
|
158
|
+
${['google', 'custom'].map(provider => html` <option value=${provider}>${provider}</option> `)}
|
|
176
159
|
</select>
|
|
177
160
|
</div>
|
|
178
161
|
|
|
179
162
|
<div id="main">
|
|
180
163
|
${this.creatable
|
|
181
164
|
? html`
|
|
182
|
-
<font-creation-card
|
|
183
|
-
class="card create"
|
|
184
|
-
@create-font=${(e) => this.onCreateFont(e)}
|
|
185
|
-
@file-drop=${(e) => this.onAttachmentDropped(e)}
|
|
186
|
-
></font-creation-card>
|
|
165
|
+
<font-creation-card class="card create" @create-font=${e => this.onCreateFont(e)}></font-creation-card>
|
|
187
166
|
`
|
|
188
167
|
: html``}
|
|
189
168
|
${fonts.map(
|
|
190
|
-
|
|
191
|
-
<div class="card" @click=${
|
|
169
|
+
font => html`
|
|
170
|
+
<div class="card" @click=${e => this.onClickSelect(font)}>
|
|
192
171
|
<div face>
|
|
193
172
|
<font .face=${font.name}>ABCDEFGHIJKLMN</font>
|
|
194
173
|
<font .face=${font.name}>abcdefghijklmn</font>
|
|
@@ -197,18 +176,16 @@ export class FontSelector extends localize(i18next)(
|
|
|
197
176
|
<div provider>${font.provider}</div>
|
|
198
177
|
<div class="button-container">
|
|
199
178
|
<mwc-icon
|
|
200
|
-
@click=${
|
|
201
|
-
e.stopPropagation()
|
|
202
|
-
this.toggleActive(font)
|
|
179
|
+
@click=${e => {
|
|
180
|
+
e.stopPropagation()
|
|
181
|
+
this.toggleActive(font)
|
|
203
182
|
}}
|
|
204
|
-
>${font.active
|
|
205
|
-
? "check_box"
|
|
206
|
-
: "check_box_outline_blank"}</mwc-icon
|
|
183
|
+
>${font.active ? 'check_box' : 'check_box_outline_blank'}</mwc-icon
|
|
207
184
|
>
|
|
208
185
|
<mwc-icon
|
|
209
|
-
@click=${
|
|
210
|
-
e.stopPropagation()
|
|
211
|
-
this.deleteFont(font)
|
|
186
|
+
@click=${e => {
|
|
187
|
+
e.stopPropagation()
|
|
188
|
+
this.deleteFont(font)
|
|
212
189
|
}}
|
|
213
190
|
>delete</mwc-icon
|
|
214
191
|
>
|
|
@@ -217,249 +194,94 @@ export class FontSelector extends localize(i18next)(
|
|
|
217
194
|
`
|
|
218
195
|
)}
|
|
219
196
|
</div>
|
|
220
|
-
|
|
197
|
+
`
|
|
221
198
|
}
|
|
222
199
|
|
|
223
200
|
async firstUpdated() {
|
|
224
|
-
var list = this.shadowRoot.querySelector(
|
|
201
|
+
var list = this.shadowRoot.querySelector('#main')
|
|
225
202
|
|
|
226
203
|
pulltorefresh({
|
|
227
204
|
container: this.shadowRoot,
|
|
228
205
|
scrollable: list,
|
|
229
206
|
refresh: () => {
|
|
230
|
-
return this.refresh()
|
|
231
|
-
}
|
|
232
|
-
})
|
|
207
|
+
return this.refresh()
|
|
208
|
+
}
|
|
209
|
+
})
|
|
233
210
|
|
|
234
211
|
/* for headroom */
|
|
235
|
-
var main = this.renderRoot.querySelector(
|
|
236
|
-
main.addEventListener(
|
|
237
|
-
this.showGotoTop = e.target.scrollTop !== 0
|
|
238
|
-
})
|
|
212
|
+
var main = this.renderRoot.querySelector('#main')
|
|
213
|
+
main.addEventListener('scroll', e => {
|
|
214
|
+
this.showGotoTop = e.target.scrollTop !== 0
|
|
215
|
+
})
|
|
239
216
|
|
|
240
|
-
var filter = this.renderRoot.querySelector(
|
|
217
|
+
var filter = this.renderRoot.querySelector('#filter')
|
|
241
218
|
|
|
242
|
-
await this.requestUpdate()
|
|
219
|
+
await this.requestUpdate()
|
|
243
220
|
|
|
244
|
-
var originPaddingTop = parseFloat(
|
|
245
|
-
|
|
246
|
-
);
|
|
247
|
-
main.style.paddingTop = filter.clientHeight + originPaddingTop + "px";
|
|
221
|
+
var originPaddingTop = parseFloat(getComputedStyle(main, null).getPropertyValue('padding-top'))
|
|
222
|
+
main.style.paddingTop = filter.clientHeight + originPaddingTop + 'px'
|
|
248
223
|
var headroom = new Headroom(filter, {
|
|
249
|
-
scroller: main
|
|
250
|
-
})
|
|
251
|
-
headroom.init()
|
|
224
|
+
scroller: main
|
|
225
|
+
})
|
|
226
|
+
headroom.init()
|
|
252
227
|
}
|
|
253
228
|
|
|
254
229
|
get creationCard() {
|
|
255
|
-
return this.shadowRoot.querySelector(
|
|
230
|
+
return this.shadowRoot.querySelector('font-creation-card')
|
|
256
231
|
}
|
|
257
232
|
|
|
258
233
|
updated(changes) {
|
|
259
|
-
if (changes.has(
|
|
260
|
-
|
|
261
|
-
if (creationCard) {
|
|
262
|
-
creationCard.reset();
|
|
263
|
-
}
|
|
234
|
+
if (changes.has('fonts')) {
|
|
235
|
+
this.creationCard?.reset()
|
|
264
236
|
}
|
|
265
237
|
}
|
|
266
238
|
|
|
267
239
|
stateChanged(state) {
|
|
268
|
-
this.fonts = state.font
|
|
240
|
+
this.fonts = state.font
|
|
269
241
|
}
|
|
270
242
|
|
|
271
243
|
refresh() {
|
|
272
|
-
return store.dispatch(
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
toggleActive(font) {
|
|
276
|
-
store.dispatch(updateFont({ id: font.id, active: !font.active }));
|
|
244
|
+
return store.dispatch(actionUpdateFontList())
|
|
277
245
|
}
|
|
278
246
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (font._files?.length > 0) {
|
|
286
|
-
let attachment = await this.attachFile(font._files[0], [
|
|
287
|
-
"fullpath",
|
|
288
|
-
"refBy",
|
|
289
|
-
]);
|
|
290
|
-
|
|
291
|
-
//font.id = attachment?.refBy
|
|
292
|
-
font.uri = attachment?.fullpath;
|
|
293
|
-
delete font._files;
|
|
247
|
+
async toggleActive(font) {
|
|
248
|
+
try {
|
|
249
|
+
await updateFont({ id: font.id, active: !font.active })
|
|
250
|
+
this.refresh()
|
|
251
|
+
} catch (e) {
|
|
252
|
+
console.error(e)
|
|
294
253
|
}
|
|
295
|
-
|
|
296
|
-
store.dispatch(createFont(font));
|
|
297
254
|
}
|
|
298
255
|
|
|
299
|
-
async
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
".eot",
|
|
306
|
-
".svg",
|
|
307
|
-
".svgz",
|
|
308
|
-
".ttf",
|
|
309
|
-
".otf",
|
|
310
|
-
].find((ext) => file.name.endsWith(ext));
|
|
311
|
-
if (!isFontFormat) {
|
|
312
|
-
isNonFontIncluded = true;
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
var alreadyExist = !!this.fonts.find(
|
|
316
|
-
(font) =>
|
|
317
|
-
font.name == file.name.replace(/\.[^/.]+$/, "").replace(".", "_")
|
|
318
|
-
);
|
|
319
|
-
if (alreadyExist) return false;
|
|
320
|
-
return true;
|
|
321
|
-
});
|
|
322
|
-
// TODO alert if non-font file is included. ex) Non-font file is excluded in upload list.
|
|
323
|
-
|
|
324
|
-
if (files.length > 0) {
|
|
325
|
-
var attached = await this.attachFiles(files, [
|
|
326
|
-
"name",
|
|
327
|
-
"fullpath",
|
|
328
|
-
"refBy",
|
|
329
|
-
]);
|
|
330
|
-
attached.forEach((attachment) => {
|
|
331
|
-
this.createFont({
|
|
332
|
-
id: attachment.refBy,
|
|
333
|
-
name: attachment.name.replace(/\.[^/.]+$/, "").replace(".", "_"), // cannot apply font correctly if '.' exists in name
|
|
334
|
-
provider: "custom",
|
|
335
|
-
active: true,
|
|
336
|
-
uri: attachment.fullpath,
|
|
337
|
-
});
|
|
338
|
-
});
|
|
256
|
+
async onCreateFont(e) {
|
|
257
|
+
try {
|
|
258
|
+
await createFont(e.detail)
|
|
259
|
+
this.refresh()
|
|
260
|
+
} catch (e) {
|
|
261
|
+
console.error(e)
|
|
339
262
|
}
|
|
340
263
|
}
|
|
341
264
|
|
|
342
|
-
/**
|
|
343
|
-
* attach a file
|
|
344
|
-
*
|
|
345
|
-
* @param { File } file file
|
|
346
|
-
* @param { Array<String> } fields fields to select from return
|
|
347
|
-
*/
|
|
348
|
-
async attachFile(file, fields = []) {
|
|
349
|
-
var attaching = await client.mutate({
|
|
350
|
-
mutation: gql`
|
|
351
|
-
mutation ($attachment: NewAttachment!) {
|
|
352
|
-
createAttachment(attachment: $attachment) {
|
|
353
|
-
id
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
`,
|
|
357
|
-
variables: {
|
|
358
|
-
attachment: { refBy: uuid(), category: "font", file },
|
|
359
|
-
},
|
|
360
|
-
context: {
|
|
361
|
-
hasUpload: true,
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
// TODO mutation 이후 query 호출 안 해도 되도록 수정
|
|
365
|
-
// fullpath 값은 getter라서 그런지 뮤테이션에서 못 받아오는 듯
|
|
366
|
-
var attached = await client.query({
|
|
367
|
-
query: gql`
|
|
368
|
-
query($id: String!) {
|
|
369
|
-
attachment(id: $id) {
|
|
370
|
-
id
|
|
371
|
-
${fields.join("\n")}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
`,
|
|
375
|
-
variables: {
|
|
376
|
-
id: attaching.data.createAttachment?.id,
|
|
377
|
-
},
|
|
378
|
-
});
|
|
379
|
-
return attached.data.attachment;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* attach multiple files
|
|
384
|
-
*
|
|
385
|
-
* @param { Array<File> } files files
|
|
386
|
-
* @param { Array<String> } fields fields to select from return
|
|
387
|
-
*/
|
|
388
|
-
async attachFiles(files, fields = []) {
|
|
389
|
-
var attaching = await client.mutate({
|
|
390
|
-
mutation: gql`
|
|
391
|
-
mutation ($attachments: [NewAttachment!]!) {
|
|
392
|
-
createAttachments(attachments: $attachments) {
|
|
393
|
-
id
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
`,
|
|
397
|
-
variables: {
|
|
398
|
-
attachments: files.map((file) => ({
|
|
399
|
-
refBy: uuid(),
|
|
400
|
-
category: "",
|
|
401
|
-
file,
|
|
402
|
-
})),
|
|
403
|
-
},
|
|
404
|
-
context: {
|
|
405
|
-
hasUpload: true,
|
|
406
|
-
},
|
|
407
|
-
});
|
|
408
|
-
// TODO mutation 이후 query 호출 안 해도 되도록 수정
|
|
409
|
-
// fullpath 값은 getter라서 그런지 뮤테이션에서 못 받아오는 듯
|
|
410
|
-
var attached = await client.query({
|
|
411
|
-
query: gql`
|
|
412
|
-
query($filters: [Filter]) {
|
|
413
|
-
attachments(filters: $filters) {
|
|
414
|
-
items {
|
|
415
|
-
id
|
|
416
|
-
${fields.join("\n")}
|
|
417
|
-
}
|
|
418
|
-
total
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
`,
|
|
422
|
-
variables: {
|
|
423
|
-
filters: {
|
|
424
|
-
name: "id",
|
|
425
|
-
operator: "in",
|
|
426
|
-
value: attaching.data.createAttachments.map(
|
|
427
|
-
(attachment) => attachment.id
|
|
428
|
-
),
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
});
|
|
432
|
-
return attached.data.attachments.items;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
265
|
async deleteFont(font) {
|
|
436
266
|
try {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
`,
|
|
443
|
-
variables: {
|
|
444
|
-
refBys: [font.id],
|
|
445
|
-
},
|
|
446
|
-
});
|
|
447
|
-
} catch (e) {}
|
|
448
|
-
|
|
449
|
-
store.dispatch(deleteFont(font));
|
|
267
|
+
await deleteFont(font.id)
|
|
268
|
+
this.refresh()
|
|
269
|
+
} catch (e) {
|
|
270
|
+
console.error(e)
|
|
271
|
+
}
|
|
450
272
|
}
|
|
451
273
|
|
|
452
274
|
onClickSelect(font) {
|
|
453
275
|
this.dispatchEvent(
|
|
454
|
-
new CustomEvent(
|
|
276
|
+
new CustomEvent('font-selected', {
|
|
455
277
|
composed: true,
|
|
456
278
|
bubbles: true,
|
|
457
279
|
detail: {
|
|
458
|
-
font
|
|
459
|
-
}
|
|
280
|
+
font
|
|
281
|
+
}
|
|
460
282
|
})
|
|
461
|
-
)
|
|
283
|
+
)
|
|
462
284
|
}
|
|
463
285
|
}
|
|
464
286
|
|
|
465
|
-
customElements.define(
|
|
287
|
+
customElements.define('font-selector', FontSelector)
|
package/src/graphql-client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import gql from 'graphql-tag'
|
|
2
|
+
|
|
3
|
+
import { client } from '@operato/graphql'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @param {Object} listParam {filters, pagination, sortings}
|
|
@@ -7,11 +8,7 @@ import gql from "graphql-tag";
|
|
|
7
8
|
export async function fetchFontList(listParam) {
|
|
8
9
|
const response = await client.query({
|
|
9
10
|
query: gql`
|
|
10
|
-
query (
|
|
11
|
-
$filters: [Filter!]
|
|
12
|
-
$pagination: Pagination
|
|
13
|
-
$sortings: [Sorting!]
|
|
14
|
-
) {
|
|
11
|
+
query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
|
|
15
12
|
fonts(filters: $filters, pagination: $pagination, sortings: $sortings) {
|
|
16
13
|
items {
|
|
17
14
|
id
|
|
@@ -20,6 +17,10 @@ export async function fetchFontList(listParam) {
|
|
|
20
17
|
uri
|
|
21
18
|
path
|
|
22
19
|
active
|
|
20
|
+
files {
|
|
21
|
+
name
|
|
22
|
+
fullpath
|
|
23
|
+
}
|
|
23
24
|
createdAt
|
|
24
25
|
updatedAt
|
|
25
26
|
}
|
|
@@ -27,10 +28,10 @@ export async function fetchFontList(listParam) {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
`,
|
|
30
|
-
variables: listParam
|
|
31
|
-
})
|
|
31
|
+
variables: listParam
|
|
32
|
+
})
|
|
32
33
|
|
|
33
|
-
return response.data && response.data.fonts
|
|
34
|
+
return response.data && response.data.fonts
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -52,18 +53,21 @@ export async function createFont(font) {
|
|
|
52
53
|
}
|
|
53
54
|
`,
|
|
54
55
|
variables: {
|
|
55
|
-
font: { active: false, ...font }
|
|
56
|
+
font: { active: false, ...font }
|
|
56
57
|
},
|
|
57
|
-
|
|
58
|
+
context: {
|
|
59
|
+
hasUpload: true
|
|
60
|
+
}
|
|
61
|
+
})
|
|
58
62
|
|
|
59
|
-
return response.data
|
|
63
|
+
return response.data
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
/**
|
|
63
67
|
* @param {Object} font Font patch
|
|
64
68
|
*/
|
|
65
69
|
export async function updateFont(font) {
|
|
66
|
-
var { id, ...patch } = font
|
|
70
|
+
var { id, ...patch } = font
|
|
67
71
|
|
|
68
72
|
const response = await client.mutate({
|
|
69
73
|
mutation: gql`
|
|
@@ -72,7 +76,10 @@ export async function updateFont(font) {
|
|
|
72
76
|
id
|
|
73
77
|
name
|
|
74
78
|
provider
|
|
75
|
-
|
|
79
|
+
files {
|
|
80
|
+
name
|
|
81
|
+
fullpath
|
|
82
|
+
}
|
|
76
83
|
path
|
|
77
84
|
active
|
|
78
85
|
createdAt
|
|
@@ -82,11 +89,14 @@ export async function updateFont(font) {
|
|
|
82
89
|
`,
|
|
83
90
|
variables: {
|
|
84
91
|
id,
|
|
85
|
-
patch
|
|
92
|
+
patch
|
|
86
93
|
},
|
|
87
|
-
|
|
94
|
+
context: {
|
|
95
|
+
hasUpload: true
|
|
96
|
+
}
|
|
97
|
+
})
|
|
88
98
|
|
|
89
|
-
return response.data
|
|
99
|
+
return response.data
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
/**
|
|
@@ -100,9 +110,9 @@ export async function deleteFont(id) {
|
|
|
100
110
|
}
|
|
101
111
|
`,
|
|
102
112
|
variables: {
|
|
103
|
-
id
|
|
104
|
-
}
|
|
105
|
-
})
|
|
113
|
+
id
|
|
114
|
+
}
|
|
115
|
+
})
|
|
106
116
|
|
|
107
|
-
return response.data
|
|
117
|
+
return response.data
|
|
108
118
|
}
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from './font-selector'
|
|
2
|
+
export * from './ox-font-selector'
|
|
3
|
+
export * from './ox-property-editor-font-selector'
|
|
4
|
+
|
|
5
|
+
export * from './redux-font-actions.js'
|
|
6
|
+
export { default as ReducerFont } from './redux-font-reducers.js'
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import '@material/mwc-icon'
|
|
2
|
+
import '@material/mwc-icon-button'
|
|
3
|
+
|
|
4
|
+
import { css, html, LitElement } from 'lit'
|
|
5
|
+
|
|
6
|
+
export class OxFileSelector extends LitElement {
|
|
7
|
+
static get styles() {
|
|
8
|
+
return [
|
|
9
|
+
css`
|
|
10
|
+
:host {
|
|
11
|
+
flex: 1;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
position: relative;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#input-box {
|
|
19
|
+
display: flex;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
input[type='file'] {
|
|
25
|
+
position: absolute;
|
|
26
|
+
width: 0px;
|
|
27
|
+
height: 0px;
|
|
28
|
+
padding: 0;
|
|
29
|
+
margin: -1px;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
clip: rect(0, 0, 0, 0);
|
|
32
|
+
border: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
label {
|
|
36
|
+
padding: unset;
|
|
37
|
+
width: 100%;
|
|
38
|
+
height: 100%;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: center;
|
|
43
|
+
|
|
44
|
+
color: var(--file-selector-color, #999);
|
|
45
|
+
font-size: inherit;
|
|
46
|
+
line-height: normal;
|
|
47
|
+
vertical-align: middle;
|
|
48
|
+
background-color: var(--file-selector-bg-color, #fdfdfd);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
border: var(--file-selector-border, 1px solid #ebebeb);
|
|
51
|
+
border-radius: var(--file-selector-border-radius, 0.25em);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* named upload */
|
|
55
|
+
.upload-name {
|
|
56
|
+
flex: 1;
|
|
57
|
+
padding: 0.5em 0.75em; /* label의 패딩값과 일치 */
|
|
58
|
+
font-size: inherit;
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
line-height: normal;
|
|
61
|
+
vertical-align: middle;
|
|
62
|
+
background-color: #f5f5f5;
|
|
63
|
+
border: 1px solid #ebebeb;
|
|
64
|
+
border-bottom-color: #e2e2e2;
|
|
65
|
+
border-radius: 0.25em;
|
|
66
|
+
-webkit-appearance: none; /* 네이티브 외형 감추기 */
|
|
67
|
+
-moz-appearance: none;
|
|
68
|
+
appearance: none;
|
|
69
|
+
}
|
|
70
|
+
`
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static get properties() {
|
|
75
|
+
return {
|
|
76
|
+
label: String,
|
|
77
|
+
accept: String,
|
|
78
|
+
showFilename: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
attribute: 'show-filename'
|
|
81
|
+
},
|
|
82
|
+
multiple: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
attribute: 'multiple'
|
|
85
|
+
},
|
|
86
|
+
_files: Array
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
constructor() {
|
|
91
|
+
super()
|
|
92
|
+
|
|
93
|
+
this._files = []
|
|
94
|
+
this.label = 'select file'
|
|
95
|
+
this.multiple = false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
render() {
|
|
99
|
+
return html`
|
|
100
|
+
<div id="input-box">
|
|
101
|
+
${this.showFilename
|
|
102
|
+
? html`
|
|
103
|
+
<input class="upload-name" value=${this._files.map(f => f.name).join(', ') || this.label} disabled />
|
|
104
|
+
`
|
|
105
|
+
: html``}
|
|
106
|
+
<label for="input-file">${this.label}</label>
|
|
107
|
+
<input
|
|
108
|
+
id="input-file"
|
|
109
|
+
type="file"
|
|
110
|
+
accept="${this.accept}"
|
|
111
|
+
class="upload-hidden"
|
|
112
|
+
?multiple=${this.multiple}
|
|
113
|
+
hidden
|
|
114
|
+
@change=${e => {
|
|
115
|
+
const el = e.currentTarget
|
|
116
|
+
this.dispatchEvent(
|
|
117
|
+
new CustomEvent('file-change', {
|
|
118
|
+
bubbles: true,
|
|
119
|
+
composed: true,
|
|
120
|
+
detail: {
|
|
121
|
+
files: el.files
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
el.value = null
|
|
127
|
+
}}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
`
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
get fileInput() {
|
|
134
|
+
return this.renderRoot.querySelector('#input-file')
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
window.customElements.define('ox-file-selector', OxFileSelector)
|
package/src/ox-font-selector.js
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import '@material/mwc-icon'
|
|
6
|
+
import './font-selector'
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { css, html, LitElement } from 'lit'
|
|
9
9
|
|
|
10
|
-
import { i18next } from
|
|
11
|
-
import { openPopup } from
|
|
10
|
+
import { i18next } from '@operato/i18n'
|
|
11
|
+
import { openPopup } from '@operato/layout'
|
|
12
12
|
|
|
13
13
|
export default class OxFontSelector extends LitElement {
|
|
14
14
|
static get properties() {
|
|
15
15
|
return {
|
|
16
16
|
value: String,
|
|
17
|
-
properties: Object
|
|
18
|
-
}
|
|
17
|
+
properties: Object
|
|
18
|
+
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
static get styles() {
|
|
@@ -26,7 +26,7 @@ export default class OxFontSelector extends LitElement {
|
|
|
26
26
|
display: inline-block;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
input[type=
|
|
29
|
+
input[type='text'] {
|
|
30
30
|
box-sizing: border-box;
|
|
31
31
|
width: 100%;
|
|
32
32
|
height: 100%;
|
|
@@ -38,8 +38,8 @@ export default class OxFontSelector extends LitElement {
|
|
|
38
38
|
top: 0;
|
|
39
39
|
right: 0;
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
]
|
|
41
|
+
`
|
|
42
|
+
]
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
render() {
|
|
@@ -47,25 +47,23 @@ export default class OxFontSelector extends LitElement {
|
|
|
47
47
|
<input
|
|
48
48
|
id="text"
|
|
49
49
|
type="text"
|
|
50
|
-
.value=${this.value ||
|
|
51
|
-
@change=${
|
|
52
|
-
.placeholder=${this.getAttribute(
|
|
50
|
+
.value=${this.value || ''}
|
|
51
|
+
@change=${e => this._onInputChanged(e)}
|
|
52
|
+
.placeholder=${this.getAttribute('placeholder') || ''}
|
|
53
53
|
/>
|
|
54
54
|
|
|
55
|
-
<mwc-icon @click=${
|
|
56
|
-
|
|
55
|
+
<mwc-icon @click=${e => this.openSelector(e)}>font_download</mwc-icon>
|
|
56
|
+
`
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
_onInputChanged(e) {
|
|
60
|
-
this.value = e.target.value
|
|
61
|
-
this.dispatchEvent(
|
|
62
|
-
new CustomEvent("change", { bubbles: true, composed: true })
|
|
63
|
-
);
|
|
60
|
+
this.value = e.target.value
|
|
61
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
openSelector() {
|
|
67
65
|
if (this.popup) {
|
|
68
|
-
delete this.popup
|
|
66
|
+
delete this.popup
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
/*
|
|
@@ -73,30 +71,28 @@ export default class OxFontSelector extends LitElement {
|
|
|
73
71
|
* 주의. value는 object일 수도 있고, string일 수도 있다.
|
|
74
72
|
* string인 경우에는 해당 보드의 id로 해석한다.
|
|
75
73
|
*/
|
|
76
|
-
var value = this.value || {}
|
|
74
|
+
var value = this.value || {}
|
|
77
75
|
|
|
78
76
|
var template = html`
|
|
79
77
|
<font-selector
|
|
80
78
|
.creatable=${true}
|
|
81
|
-
@font-selected=${async
|
|
82
|
-
var font = e.detail.font
|
|
83
|
-
this.value = font.name
|
|
79
|
+
@font-selected=${async e => {
|
|
80
|
+
var font = e.detail.font
|
|
81
|
+
this.value = font.name
|
|
84
82
|
|
|
85
|
-
this.dispatchEvent(
|
|
86
|
-
new CustomEvent("change", { bubbles: true, composed: true })
|
|
87
|
-
);
|
|
83
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))
|
|
88
84
|
|
|
89
|
-
this.popup && this.popup.close()
|
|
85
|
+
this.popup && this.popup.close()
|
|
90
86
|
}}
|
|
91
87
|
></font-selector>
|
|
92
|
-
|
|
88
|
+
`
|
|
93
89
|
|
|
94
90
|
this.popup = openPopup(template, {
|
|
95
91
|
backdrop: true,
|
|
96
|
-
size:
|
|
97
|
-
title: i18next.t(
|
|
98
|
-
})
|
|
92
|
+
size: 'large',
|
|
93
|
+
title: i18next.t('title.select font')
|
|
94
|
+
})
|
|
99
95
|
}
|
|
100
96
|
}
|
|
101
97
|
|
|
102
|
-
customElements.define(
|
|
98
|
+
customElements.define('ox-font-selector', OxFontSelector)
|
|
@@ -2,24 +2,16 @@
|
|
|
2
2
|
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import './ox-font-selector'
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import { html } from 'lit'
|
|
8
|
+
|
|
9
|
+
import { OxPropertyEditor } from '@operato/property-editor'
|
|
9
10
|
|
|
10
11
|
export class OxPropertyEditorFontSelector extends OxPropertyEditor {
|
|
11
12
|
editorTemplate() {
|
|
12
|
-
return html`
|
|
13
|
-
<ox-font-selector
|
|
14
|
-
id="editor"
|
|
15
|
-
.value=${this.value}
|
|
16
|
-
.properties=${this.property}
|
|
17
|
-
></ox-font-selector>
|
|
18
|
-
`;
|
|
13
|
+
return html` <ox-font-selector id="editor" .value=${this.value} .properties=${this.property}></ox-font-selector> `
|
|
19
14
|
}
|
|
20
15
|
}
|
|
21
16
|
|
|
22
|
-
customElements.define(
|
|
23
|
-
"ox-property-editor-font-selector",
|
|
24
|
-
OxPropertyEditorFontSelector
|
|
25
|
-
);
|
|
17
|
+
customElements.define('ox-property-editor-font-selector', OxPropertyEditorFontSelector)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as client from './graphql-client'
|
|
2
|
+
|
|
3
|
+
export const UPDATE_FONT_LIST = 'UPDATE_FONT_LIST'
|
|
4
|
+
export const CLEAR_FONT_LIST = 'CLEAR_FONT_LIST'
|
|
5
|
+
|
|
6
|
+
export const actionUpdateFontList = listParams => async dispatch => {
|
|
7
|
+
try {
|
|
8
|
+
const fonts = await client.fetchFontList(listParams || { filters: [] })
|
|
9
|
+
|
|
10
|
+
dispatch({
|
|
11
|
+
type: UPDATE_FONT_LIST,
|
|
12
|
+
list: fonts && fonts.items
|
|
13
|
+
})
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error(error)
|
|
16
|
+
dispatch({
|
|
17
|
+
type: CLEAR_FONT_LIST
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import WebFont from 'webfontloader'
|
|
2
|
+
|
|
3
|
+
import { CLEAR_FONT_LIST, UPDATE_FONT_LIST } from './redux-font-actions.js'
|
|
4
|
+
|
|
5
|
+
const reducerFont = (state = [], action) => {
|
|
6
|
+
switch (action.type) {
|
|
7
|
+
case UPDATE_FONT_LIST:
|
|
8
|
+
let newState = action.list
|
|
9
|
+
let activatedFonts = newState.filter(font => font.active)
|
|
10
|
+
|
|
11
|
+
let googles = []
|
|
12
|
+
let customs = []
|
|
13
|
+
let customFontCSS = ''
|
|
14
|
+
|
|
15
|
+
activatedFonts.forEach(font => {
|
|
16
|
+
const { name, provider, files, uri } = font
|
|
17
|
+
|
|
18
|
+
if (provider === 'google') {
|
|
19
|
+
googles.push(name)
|
|
20
|
+
} else if (provider === 'custom') {
|
|
21
|
+
customs.push(name)
|
|
22
|
+
|
|
23
|
+
if (files && files.length > 0) {
|
|
24
|
+
customFontCSS += files
|
|
25
|
+
.map(file => {
|
|
26
|
+
const { name: filename, fullpath } = file
|
|
27
|
+
const bold = filename.toUpperCase().indexOf('BOLD') !== -1
|
|
28
|
+
|
|
29
|
+
return `@font-face {
|
|
30
|
+
font-family: '${name}';
|
|
31
|
+
src: local('${name}'), url(${fullpath});
|
|
32
|
+
font-weight: ${bold ? 'bold' : 'normal'};
|
|
33
|
+
}
|
|
34
|
+
`
|
|
35
|
+
})
|
|
36
|
+
.join('\n')
|
|
37
|
+
} else {
|
|
38
|
+
customFontCSS += `@font-face {
|
|
39
|
+
font-family: '${name}';
|
|
40
|
+
src: local('${name}')${uri ? `, url(${uri})` : ''};
|
|
41
|
+
}
|
|
42
|
+
`
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
let style = document.head.querySelector('#custom-fonts')
|
|
48
|
+
if (!style) {
|
|
49
|
+
style = document.createElement('style')
|
|
50
|
+
style.id = 'custom-fonts'
|
|
51
|
+
style.type = 'text/css'
|
|
52
|
+
document.head.appendChild(style)
|
|
53
|
+
}
|
|
54
|
+
style.innerHTML = customFontCSS
|
|
55
|
+
|
|
56
|
+
// TODO: typekit 등 타 서비스 지원
|
|
57
|
+
let WebFontConfig = {}
|
|
58
|
+
if (googles.length) {
|
|
59
|
+
WebFontConfig.google = {
|
|
60
|
+
families: googles
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (customs.length) {
|
|
64
|
+
WebFontConfig.custom = {
|
|
65
|
+
families: customs
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (Object.keys(WebFontConfig).length) WebFont.load(WebFontConfig)
|
|
69
|
+
|
|
70
|
+
return newState
|
|
71
|
+
|
|
72
|
+
case CLEAR_FONT_LIST:
|
|
73
|
+
return []
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
return state
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default reducerFont
|