@operato/contact 7.1.27 → 7.1.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.
@@ -1,189 +0,0 @@
1
- import './ox-pfp-view.js'
2
-
3
- import { html, css, LitElement } from 'lit'
4
- import { customElement, property } from 'lit/decorators.js'
5
- import { Contact, ContactField, ContactItem } from './ox-contact'
6
-
7
- @customElement('ox-contact-view')
8
- export class OxContactView extends LitElement {
9
- static styles = css`
10
- :host {
11
- display: block;
12
- --md-icon-size: 16px;
13
-
14
- color: var(--md-sys-color-on-surface);
15
- background-color: var(--md-sys-color-surface);
16
- }
17
-
18
- :host > div {
19
- padding: var(--spacing-medium, 8px);
20
- display: block;
21
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
22
- font-size: 0.9em;
23
- text-transform: capitalize;
24
- }
25
-
26
- :host > div > div {
27
- padding: 4px 0;
28
- box-sizing: border-box;
29
-
30
- display: flex;
31
- flex-direction: row;
32
- gap: 10px;
33
- }
34
-
35
- :host > div > div:hover {
36
- position: relative;
37
- }
38
-
39
- :host > div > div:hover::before {
40
- content: '';
41
- display: block;
42
- position: absolute;
43
- text-align: left;
44
- line-height: 24px;
45
- top: 0;
46
- right: 0;
47
- width: 100%;
48
- height: 100%;
49
- opacity: 0.15;
50
- background-image: linear-gradient(var(--md-sys-color-primary, gray), var(--md-sys-color-primary, gray));
51
- }
52
-
53
- [data-item='label'] {
54
- width: 80px;
55
- text-align: right;
56
- color: var(--md-sys-color-primary, #017e7f);
57
- }
58
-
59
- [data-item='value'] {
60
- flex: 1;
61
- text-transform: none;
62
- }
63
-
64
- :host > div[name] {
65
- display: flex;
66
- align-items: center;
67
- gap: 15px;
68
- font-weight: bold;
69
- font-size: 1.4em;
70
- }
71
-
72
- :host ox-pfp-view {
73
- display: inline-block;
74
-
75
- --ox-pfp-size: 75px;
76
- }
77
-
78
- :host > div[name] > div[name-content] {
79
- flex: 1;
80
-
81
- display: flex;
82
- flex-direction: column;
83
- }
84
-
85
- div[data-type='email'] md-icon::before {
86
- content: 'mail_outline';
87
- }
88
-
89
- div[data-type='phone'] md-icon::before {
90
- content: 'phone';
91
- }
92
-
93
- div[data-type='address'] md-icon::before {
94
- content: 'place';
95
- }
96
-
97
- div[data-type='department'] md-icon::before {
98
- content: 'diversity_3';
99
- }
100
-
101
- div[data-type='company'] md-icon::before {
102
- content: 'business';
103
- }
104
-
105
- div[data-type='etc'] md-icon::before {
106
- content: 'feed';
107
- }
108
-
109
- div[note] md-icon::before {
110
- content: 'subject';
111
- }
112
-
113
- :host > div > [name-content] {
114
- gap: 3px;
115
- }
116
-
117
- div md-icon {
118
- position: relative;
119
- top: 3px;
120
- margin-right: 3px;
121
- opacity: 0.5;
122
- color: var(--md-sys-color-on-primary-container, #333);
123
- }
124
-
125
- [name-content] div {
126
- color: var(--md-sys-color-on-primary-container, #333);
127
- font-size: 1.2em;
128
- }
129
-
130
- [name-content] [company] {
131
- color: var(--md-sys-color-on-secondary-container, #666);
132
- font-weight: normal;
133
- font-size: 0.9em;
134
- }
135
- `
136
-
137
- @property({ type: Object }) contact: Contact = {}
138
-
139
- render() {
140
- const { profile, items = [], name, company, note } = this.contact || {}
141
- var sorted: { [type: string]: ContactItem[] } = {}
142
-
143
- items.forEach(item => {
144
- if (!sorted[item.type as string]) {
145
- sorted[item.type] = [item]
146
- } else {
147
- sorted[item.type as string].push(item)
148
- }
149
- })
150
-
151
- return html`
152
- <div name>
153
- <ox-pfp-view .profile=${profile} .name=${name}></ox-pfp-view>
154
-
155
- <div name-content>
156
- <div>
157
- <span data-item="value">${name}</span>
158
- </div>
159
- <div company>
160
- <span data-item="value">${company}</span>
161
- </div>
162
- </div>
163
- </div>
164
-
165
- ${['department', 'email', 'phone', 'address', 'company', 'etc']
166
- .map(type => sorted[type])
167
- .filter(items => items && items.length > 0)
168
- .map(
169
- items =>
170
- html`<div data-type=${items[0].type}>
171
- <md-icon></md-icon>
172
- ${items[0].type}
173
- ${items.map(
174
- item =>
175
- html`<div>
176
- <label data-item="label"> ${item.label}</label>
177
- <span data-item="value">${item.value}</span>
178
- </div>`
179
- )}
180
- </div>`
181
- )}
182
- <div note>
183
- <md-icon></md-icon>
184
- note
185
- <div>${note || ''}</div>
186
- </div>
187
- `
188
- }
189
- }
package/src/ox-contact.ts DELETED
@@ -1,116 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import './ox-contact-edit.js'
3
- import './ox-contact-view.js'
4
-
5
- import { html, css, LitElement } from 'lit'
6
- import { customElement, property, query, state } from 'lit/decorators.js'
7
-
8
- import { i18next } from '@operato/i18n'
9
- import { CommonHeaderStyles } from '@operato/styles'
10
-
11
- import { OxContactEdit } from './ox-contact-edit.js'
12
- import { Profile } from './ox-pfp-view.js'
13
-
14
- export enum ContactField {
15
- JobTitle = 'job-title',
16
- Phone = 'phone',
17
- Address = 'address',
18
- Email = 'email',
19
- Birthday = 'birthday',
20
- Profile = 'profile',
21
- Picture = 'picture',
22
- Department = 'department',
23
- Homepage = 'homepage'
24
- }
25
-
26
- export enum ContactLabel {
27
- home = 'home',
28
- work = 'work',
29
- other = 'other',
30
- mobile = 'mobile'
31
- }
32
-
33
- export type ContactItem = {
34
- id?: string
35
- type: ContactField
36
- label: string
37
- value: string
38
- }
39
-
40
- export type Contact = {
41
- id?: string
42
- profile?: Profile
43
- name?: string
44
- company?: string
45
- items?: ContactItem[]
46
- note?: string
47
- }
48
-
49
- @customElement('ox-contact')
50
- export class OxContact extends LitElement {
51
- static styles = [
52
- CommonHeaderStyles,
53
- css`
54
- :host {
55
- display: flex;
56
- flex-direction: column;
57
- color: var(--md-sys-color-on-surface);
58
- background-color: var(--md-sys-color-surface);
59
- }
60
-
61
- ox-contact-view,
62
- ox-contact-edit {
63
- padding: var(--pading-default);
64
- flex: 1;
65
- }
66
- `
67
- ]
68
-
69
- @property({ type: Object }) contact: Contact = {}
70
-
71
- @state() editMode?: boolean = false
72
-
73
- @query('ox-contact-edit') editor!: OxContactEdit
74
-
75
- render() {
76
- return html`
77
- <div container>
78
- ${
79
- this.editMode
80
- ? html`<ox-contact-edit
81
- .contact=${this.contact}
82
- @edit-cancel=${() => (this.editMode = false)}
83
- @edit-done=${(e: CustomEvent) => {
84
- this.contact = e.detail
85
- this.editMode = false
86
- }}
87
- ></ox-contact-edit>`
88
- : html` <ox-contact-view .contact=${this.contact}></ox-contact-view> `
89
- }
90
- </div>
91
-
92
- <div class="footer">
93
- ${
94
- this.editMode
95
- ? html`
96
- <button @click=${() => this.editor.reset()}>
97
- <md-icon>restart_alt</md-icon>${i18next.t('button.reset')}
98
- </button>
99
- <div filler></div>
100
- <button @click=${() => this.editor.cancel()}>
101
- <md-icon>cancel</md-icon>${i18next.t('button.cancel')}
102
- </button>
103
- <button @click=${() => this.editor.save()}>
104
- <md-icon>done</md-icon>${i18next.t('button.confirm')}
105
- </button>
106
- `
107
- : html`
108
- <button @click=${() => (this.editMode = true)}>
109
- <md-icon>edit</md-icon>${i18next.t('button.edit')}
110
- </button>
111
- `
112
- }
113
- </div>
114
- </div>`
115
- }
116
- }
@@ -1,363 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { html, css, LitElement, PropertyValues } from 'lit'
4
- import { customElement, property, query, state } from 'lit/decorators.js'
5
- import { Profile } from './ox-pfp-view'
6
- import { FileDropHelper } from '@operato/utils'
7
-
8
- function getPoint(e: Event): { x: number; y: number } | undefined {
9
- if ((e as MouseEvent).button == 0) {
10
- return {
11
- x: (e as MouseEvent).clientX,
12
- y: (e as MouseEvent).clientY
13
- }
14
- } else if ((e as TouchEvent).touches?.length == 1) {
15
- const touch = (e as TouchEvent).touches[0]
16
- return {
17
- x: touch.clientX,
18
- y: touch.clientY
19
- }
20
- } else {
21
- return
22
- }
23
- }
24
-
25
- @customElement('ox-pfp-edit')
26
- export class OxPfpEdit extends LitElement {
27
- static styles = css`
28
- :host {
29
- display: inline-block;
30
- overflow: hidden;
31
- aspect-ratio: 1 / 1;
32
-
33
- height: var(--ox-pfp-size, 100px);
34
- width: var(--ox-pfp-size, 100px);
35
- }
36
-
37
- [content] {
38
- display: flex;
39
- align-items: center;
40
- justify-content: center;
41
- width: 100%;
42
- height: 100%;
43
- }
44
-
45
- [circle] {
46
- width: 90%;
47
- height: 90%;
48
- position: relative;
49
- }
50
-
51
- [circle]::after {
52
- position: absolute;
53
- content: '';
54
- width: 100%;
55
- height: 100%;
56
- box-shadow: 0 0 0 1000px lightgray;
57
- border-radius: 50%;
58
- opacity: 0.9;
59
- }
60
-
61
- [circle]::before {
62
- content: '';
63
- display: block;
64
- position: absolute;
65
- text-align: left;
66
- line-height: 24px;
67
- top: 0;
68
- right: 0;
69
- width: 100%;
70
- height: 100%;
71
- background-repeat: no-repeat;
72
- background-image: var(
73
- --background-image,
74
- linear-gradient(
75
- var(--md-sys-color-on-primary-container, lightgray),
76
- var(--md-sys-color-on-primary-container, lightgray)
77
- )
78
- );
79
- transform: var(--image-transform, '');
80
- background-size: 100% 100%;
81
- }
82
-
83
- [monogram] {
84
- width: 100%;
85
- height: 100%;
86
- border-radius: 50%;
87
- border: 1px solid darkgray;
88
- box-sizing: border-box;
89
- padding: 0;
90
- overflow: hidden;
91
- background-color: gray;
92
- color: white;
93
-
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- }
98
-
99
- [monogram] div {
100
- flex: 1;
101
- text-transform: uppercase;
102
- font-size: 2em;
103
- font-family: system-ui;
104
- text-align: center;
105
- }
106
-
107
- [file-load] {
108
- position: absolute;
109
- left: 0;
110
- top: 0;
111
-
112
- display: flex;
113
- place-content: center;
114
- }
115
-
116
- [file-load]:hover {
117
- opacity: 50%;
118
- }
119
-
120
- #input-file {
121
- display: none;
122
- }
123
-
124
- label {
125
- display: flex;
126
- align-content: center;
127
- }
128
-
129
- md-icon {
130
- align-self: center;
131
-
132
- color: var(--file-uploader-icon-color, black);
133
- --md-icon-size: var(--file-uploader-icon-size, 24px);
134
- }
135
- `
136
-
137
- @property({ type: Object }) profile: Profile = {}
138
- @property({ type: String }) name?: string
139
-
140
- @query('[circle]') circle!: HTMLDivElement
141
-
142
- private dragStart?: { x: number; y: number }
143
-
144
- private dragEndHandler = this.onDragEnd.bind(this) as EventListener
145
- private dragMoveHandler = this.onDragMove.bind(this) as EventListener
146
- private dragStartHandler = this.onDragStart.bind(this) as EventListener
147
- private wheelEventHandler = this.onWheelEvent.bind(this) as EventListener
148
- private dropFileHandler = this.onDropFile.bind(this) as EventListener
149
-
150
- connectedCallback(): void {
151
- super.connectedCallback()
152
-
153
- FileDropHelper.set(this)
154
-
155
- this.addEventListener('mousewheel', this.wheelEventHandler, false)
156
-
157
- this.addEventListener('mousedown', this.dragStartHandler)
158
- this.addEventListener('touchstart', this.dragStartHandler)
159
-
160
- document.addEventListener('mouseup', this.dragEndHandler)
161
- document.addEventListener('touchend', this.dragEndHandler)
162
- document.addEventListener('touchcancel', this.dragEndHandler)
163
- document.addEventListener('mousemove', this.dragMoveHandler)
164
- document.addEventListener('touchmove', this.dragMoveHandler)
165
-
166
- this.addEventListener('file-drop', this.dropFileHandler)
167
- }
168
-
169
- disconnectedCallback() {
170
- this.removeEventListener('mousewheel', this.wheelEventHandler, false)
171
-
172
- this.removeEventListener('mousedown', this.dragStartHandler!)
173
- this.removeEventListener('touchstart', this.dragStartHandler!)
174
-
175
- document.removeEventListener('mouseup', this.dragEndHandler!)
176
- document.removeEventListener('touchend', this.dragEndHandler!)
177
- document.removeEventListener('touchcancel', this.dragEndHandler!)
178
- document.removeEventListener('mousemove', this.dragMoveHandler!)
179
- document.removeEventListener('touchmove', this.dragMoveHandler!)
180
-
181
- this.removeEventListener('file-drop', this.dropFileHandler)
182
-
183
- super.disconnectedCallback()
184
- }
185
-
186
- render() {
187
- return html`
188
- <div content>
189
- ${this.profile?.picture
190
- ? html`<div circle></div>`
191
- : html`<div monogram><div>${this.name?.replace(/\s/g, '').slice(0, 2)}</div></div>`}
192
- </div>
193
-
194
- <div file-load>
195
- <label>
196
- <input
197
- id="input-file"
198
- type="file"
199
- accept="image/*"
200
- hidden
201
- capture="environment"
202
- @change=${(e: Event) => this.onChangeFile(e)}
203
- />
204
- <md-icon title="select image">image_search</md-icon>
205
- </label>
206
- </div>
207
-
208
- <slot></slot>
209
- `
210
- }
211
-
212
- updated(changes: PropertyValues<this>) {
213
- const { picture, zoom = 1, left = 0, top = 0 } = this.profile || {}
214
-
215
- if (picture) {
216
- const style = this.style
217
-
218
- style.setProperty('--background-image', `url('${picture}')`)
219
- style.setProperty('--image-transform', `translate(${left}%, ${top}%) scale(${zoom}, ${zoom})`)
220
- }
221
- }
222
-
223
- get value() {
224
- return this.profile
225
- }
226
-
227
- set value(value: Profile) {
228
- this.profile = value
229
- }
230
-
231
- onWheelEvent(e: Event) {
232
- e.preventDefault()
233
-
234
- var delta = Math.max(-1, Math.min(1, (e as WheelEvent).deltaY || -(e as WheelEvent).detail))
235
-
236
- const { top = 0, left = 0, zoom = 1, picture, file } = this.profile || {}
237
- this.profile = {
238
- top,
239
- left,
240
- zoom: zoom * (1 - delta / 20),
241
- picture,
242
- file
243
- }
244
-
245
- this.dispatchEvent(
246
- new CustomEvent('change', {
247
- detail: this.profile
248
- })
249
- )
250
- }
251
-
252
- onDragStart(e: Event) {
253
- const point = getPoint(e)
254
-
255
- if (point) {
256
- this.dragStart = point
257
- e.stopPropagation()
258
- return false
259
- }
260
- }
261
-
262
- onDragMove(e: Event) {
263
- if (!this.dragStart) {
264
- return false
265
- }
266
-
267
- const point = getPoint(e)
268
-
269
- if (!point) {
270
- return false
271
- }
272
-
273
- e.stopPropagation()
274
- e.preventDefault()
275
-
276
- const dragStart = point
277
- var { x, y } = point
278
-
279
- x -= this.dragStart.x
280
- y -= this.dragStart.y
281
-
282
- this.dragStart = dragStart
283
-
284
- const { top = 0, left = 0, zoom = 1, picture, file } = this.profile || {}
285
- const { offsetHeight, offsetWidth } = this
286
-
287
- this.profile = {
288
- top: top + (y / offsetHeight) * 100,
289
- left: left + (x / offsetWidth) * 100,
290
- zoom,
291
- picture,
292
- file
293
- }
294
-
295
- this.dispatchEvent(
296
- new CustomEvent('change', {
297
- detail: this.profile
298
- })
299
- )
300
-
301
- return false
302
- }
303
-
304
- onDragEnd(e: Event) {
305
- if (this.dragStart) {
306
- e.stopPropagation()
307
- e.preventDefault()
308
-
309
- delete this.dragStart
310
- }
311
- }
312
-
313
- onDropFile(e: Event) {
314
- const dropFiles = (e as CustomEvent).detail
315
- const imageFile = dropFiles[0]
316
- if (!imageFile) {
317
- return
318
- }
319
-
320
- const picture = URL.createObjectURL(imageFile)
321
-
322
- this.profile = {
323
- left: 0,
324
- top: 0,
325
- zoom: 1,
326
- picture,
327
- file: imageFile
328
- }
329
- }
330
-
331
- onChangeFile(e: Event) {
332
- const fileInput = e.currentTarget as HTMLInputElement
333
- const imageFile = [...Array.from(fileInput.files as FileList)][0]
334
- if (!imageFile) {
335
- return
336
- }
337
-
338
- const picture = URL.createObjectURL(imageFile)
339
-
340
- this.profile = {
341
- left: 0,
342
- top: 0,
343
- zoom: 1,
344
- picture,
345
- file: imageFile
346
- }
347
-
348
- fileInput.files = null
349
- }
350
-
351
- fit() {
352
- this.profile = {
353
- ...this.profile,
354
- left: 0,
355
- top: 0,
356
- zoom: 1
357
- }
358
- }
359
-
360
- clear() {
361
- this.profile = {}
362
- }
363
- }