@operato/contact 8.0.0-beta.0 → 8.0.0-beta.2

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,260 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import './ox-pfp.js'
3
-
4
- import { html, css, LitElement, PropertyValues } from 'lit'
5
- import { customElement, property, state, query, queryAll } from 'lit/decorators.js'
6
- import { Contact, ContactField, ContactItem } from './ox-contact'
7
- import { ScrollbarStyles } from '@operato/styles'
8
- import { i18next } from '@operato/i18n'
9
- import { OxPfp } from './ox-pfp.js'
10
-
11
- @customElement('ox-contact-edit')
12
- export class OxContactEdit extends LitElement {
13
- static styles = [
14
- ScrollbarStyles,
15
- css`
16
- :host {
17
- display: block;
18
- padding: 25px;
19
- }
20
-
21
- input,
22
- select,
23
- textarea {
24
- padding: 8px;
25
- border-radius: 4px;
26
- border: 1px solid var(--md-sys-color-outline, #ccc);
27
- background-color: #fff;
28
- color: var(--md-sys-color-on-surface);
29
- font-size: 16px; /* for iPhone */
30
- box-shadow: 0 1px 1px 0px rgba(0, 0, 0, 0.1);
31
- transition:
32
- border-color 0.3s ease,
33
- box-shadow 0.3s ease;
34
- }
35
-
36
- input:focus,
37
- select:focus,
38
- textarea:focus {
39
- border-color: var(--md-sys-color-primary, #6200ea);
40
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
41
- outline: none;
42
- }
43
-
44
- :host > div {
45
- padding: 10px 0;
46
- display: block;
47
- border-bottom: 1px solid blue;
48
- }
49
-
50
- :host > div > div {
51
- padding: 4px 0;
52
- box-sizing: border-box;
53
-
54
- display: flex;
55
- flex-direction: row;
56
- gap: 10px;
57
- align-items: center;
58
- }
59
-
60
- :host > div > div:hover {
61
- position: relative;
62
- }
63
-
64
- [data-item='label'] {
65
- width: 100px;
66
- text-align: right;
67
- }
68
-
69
- [data-item='value'] {
70
- flex: 1;
71
- }
72
-
73
- :host > div[name] {
74
- display: flex;
75
- align-items: center;
76
- gap: 10px;
77
- font-weight: bold;
78
- font-size: 1.4em;
79
- }
80
-
81
- :host ox-pfp {
82
- display: inline-block;
83
- width: 100px;
84
- height: 100px;
85
- }
86
-
87
- :host > div[name] > div[name-content] {
88
- flex: 1;
89
-
90
- display: grid;
91
- grid-template-columns: minmax(auto, 160px) 1fr;
92
- gap: var(--spacing-medium);
93
- align-items: center;
94
-
95
- span {
96
- text-align: right;
97
- }
98
- }
99
-
100
- div[field] {
101
- display: flex;
102
- flex-direction: row;
103
- align-items: center;
104
- gap: 10px;
105
- }
106
-
107
- div[field] > span {
108
- width: 100px;
109
- text-align: right;
110
- }
111
-
112
- div[field] > input {
113
- flex: 1;
114
- }
115
-
116
- textarea {
117
- width: 100%;
118
- min-height: 100px;
119
- box-sizing: border-box;
120
- resize: none;
121
- }
122
- `
123
- ]
124
-
125
- @property({ type: Object }) contact: Contact = {}
126
-
127
- @state() private stageContact: Contact = JSON.parse(JSON.stringify(this.contact))
128
-
129
- @query('#name') name!: HTMLTextAreaElement
130
- @query('#company') company!: HTMLTextAreaElement
131
- @query('#note') note!: HTMLTextAreaElement
132
- @query('ox-pfp') pfp!: OxPfp
133
- @queryAll('[item-field]') fields!: NodeListOf<HTMLDivElement>
134
-
135
- render() {
136
- const { profile, items = [], name, company, note } = this.stageContact || {}
137
- var sorted: { [type: string]: ContactItem[] } = {}
138
-
139
- items.forEach(item => {
140
- if (!sorted[item.type as string]) {
141
- sorted[item.type] = [item]
142
- } else {
143
- sorted[item.type as string].push(item)
144
- }
145
- })
146
-
147
- return html`
148
- <div name>
149
- <ox-pfp .profile=${profile} .name=${name}></ox-pfp>
150
-
151
- <div name-content>
152
- <span>${i18next.t('label.name')}</span>
153
- <input type="text" id="name" .value=${name ?? ''} @change=${(e: Event) => this.buildStageContact()} />
154
- <span>${i18next.t('label.company')}</span>
155
- <input type="text" id="company" .value=${company ?? ''} @change=${(e: Event) => this.buildStageContact()} />
156
- </div>
157
- </div>
158
- ${['department', 'email', 'phone', 'address'].map(type => {
159
- var items = [...(sorted[type] || []), { type: type as ContactField, label: 'work', value: '' }]
160
-
161
- return html`
162
- <div data-type=${type}>
163
- ${type}
164
- ${items.map(
165
- item =>
166
- html`<div @change=${(e: Event) => this.onChangeItem(e, item)} .item=${item} item-field>
167
- ${item.value
168
- ? html`<md-icon
169
- @click=${() => {
170
- item.value = ''
171
- this.buildStageContact()
172
- }}
173
- >cancel</md-icon
174
- >`
175
- : html`<md-icon></md-icon>`}
176
- <select .value=${item.label} data-item="label">
177
- ${['home', 'work', 'other', 'mobile'].map(
178
- option => html` <option value=${option} ?selected=${option === item.label}>${option}</option>`
179
- )}
180
- </select>
181
- <input type="text" .value=${item.value} data-item="value" />
182
- </div>`
183
- )}
184
- </div>
185
- `
186
- })}
187
- <div note>
188
- note
189
- <textarea id="note" .value=${note || ''} @change=${() => this.buildStageContact()}></textarea>
190
- </div>
191
- `
192
- }
193
-
194
- updated(changes: PropertyValues<this>) {
195
- if (changes.has('contact')) {
196
- this.stageContact = JSON.parse(JSON.stringify(this.contact))
197
- }
198
- }
199
-
200
- buildItems() {
201
- const items: ContactItem[] = []
202
-
203
- this.fields.forEach(fieldElement => {
204
- const item = (fieldElement as any).item
205
- if (item.value) {
206
- items.push(item)
207
- }
208
- })
209
-
210
- return items
211
- }
212
-
213
- buildStageContact() {
214
- this.stageContact = {
215
- ...this.stageContact,
216
- profile: this.pfp.profile,
217
- name: this.name.value,
218
- company: this.company.value,
219
- note: this.note.value,
220
- items: this.buildItems()
221
- }
222
- }
223
-
224
- onChangeItem(e: Event, item: ContactItem) {
225
- const target = e.currentTarget as HTMLElement
226
- const labelElement = target.querySelector('[data-item="label"]') as HTMLSelectElement
227
- const valueElement = target.querySelector('[data-item="value"]') as HTMLInputElement
228
-
229
- item.label = labelElement.value
230
- item.value = valueElement.value
231
-
232
- if (e.target === valueElement || item.value) {
233
- this.buildStageContact()
234
- }
235
- }
236
-
237
- save() {
238
- this.buildStageContact()
239
-
240
- this.dispatchEvent(
241
- new CustomEvent('edit-done', {
242
- detail: this.stageContact
243
- })
244
- )
245
- }
246
-
247
- cancel() {
248
- this.dispatchEvent(
249
- new CustomEvent('edit-cancel', {
250
- detail: this.stageContact
251
- })
252
- )
253
- }
254
-
255
- reset() {
256
- this.buildStageContact()
257
-
258
- this.stageContact = JSON.parse(JSON.stringify(this.contact))
259
- }
260
- }
@@ -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
- }