@things-factory/gallery 10.1.256 → 10.1.258

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.
@@ -10,9 +10,12 @@ import '@operato/input/ox-input-file.js'
10
10
  import '@operato/input/ox-input-select-buttons.js'
11
11
  import '@operato/popup/ox-popup-actions.js'
12
12
 
13
+ import gql from 'graphql-tag'
13
14
  import { css, html, LitElement, nothing } from 'lit'
14
15
  import { customElement, property, query, state } from 'lit/decorators.js'
15
16
 
17
+ import { QueryController } from '@operato/graphql'
18
+
16
19
  import { i18next, localize } from '@operato/i18n'
17
20
  import { notify } from '@operato/layout'
18
21
  import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'
@@ -226,7 +229,8 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
226
229
  @state() private tagText = ''
227
230
  /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
228
231
  @state() private tagRefusal = ''
229
- @state() private suggestions: { tag: string; count: number }[] = []
232
+ /** The tag text the suggestions are for - the typed text once typing pauses. */
233
+ @state() private suggestFor?: string
230
234
  @state() private chosenSpace: Space = 'COMPANY'
231
235
  /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
232
236
  @state() private shared = false
@@ -242,6 +246,16 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
242
246
 
243
247
  private suggestTimer?: ReturnType<typeof setTimeout>
244
248
 
249
+ /* The tags used before that begin like the one typed; the last ones stay while the next are read. */
250
+ private suggestionsRead = new QueryController(this, gql`query ($text: String) { galleryTags(text: $text) { tag count } }`, {
251
+ variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),
252
+ keepPrevious: true
253
+ })
254
+
255
+ private get suggestions(): { tag: string; count: number }[] {
256
+ return this.suggestionsRead.data?.galleryTags ?? []
257
+ }
258
+
245
259
  render() {
246
260
  const total = this.kept.length + this.added.length
247
261
  const full = total >= MAX_PHOTOS
@@ -507,13 +521,7 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
507
521
  }
508
522
  this.tagText = value
509
523
  clearTimeout(this.suggestTimer)
510
- this.suggestTimer = setTimeout(async () => {
511
- try {
512
- this.suggestions = await galleryApi.tags(this.tagText)
513
- } catch {
514
- this.suggestions = []
515
- }
516
- }, 200)
524
+ this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200)
517
525
  }
518
526
 
519
527
  private tagKey(e: KeyboardEvent) {
@@ -9,9 +9,12 @@ import '@material/web/button/text-button.js'
9
9
  import '@material/web/icon/icon.js'
10
10
  import '@operato/popup/ox-popup-actions.js'
11
11
 
12
+ import gql from 'graphql-tag'
12
13
  import { css, html, LitElement, nothing } from 'lit'
13
14
  import { customElement, property, state } from 'lit/decorators.js'
14
15
 
16
+ import { QueryController } from '@operato/graphql'
17
+
15
18
  import { i18next, localize } from '@operato/i18n'
16
19
  import { notify } from '@operato/layout'
17
20
  import { OxPrompt } from '@operato/popup/ox-prompt.js'
@@ -195,12 +198,21 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
195
198
  @property({ attribute: false }) post!: Post
196
199
 
197
200
  @state() private index = 0
198
- @state() private likers?: { id: string; name?: string }[]
201
+ /** Who liked it is shown under the heart once asked. */
202
+ @state() private showingLikers = false
199
203
  @state() private hiding = false
200
204
  @state() private reason = ''
201
205
  @state() private burst = 0
202
206
  @state() private busy = false
203
207
 
208
+ private likersRead = new QueryController(this, gql`query ($id: String!) { galleryLikers(id: $id) { id name } }`, {
209
+ variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)
210
+ })
211
+
212
+ private get likers(): { id: string; name?: string }[] | undefined {
213
+ return this.likersRead.data?.galleryLikers
214
+ }
215
+
204
216
  render() {
205
217
  const post = this.post
206
218
  if (!post) return nothing
@@ -326,7 +338,7 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
326
338
  try {
327
339
  const state = await galleryApi.like(post.id, like)
328
340
  this.post = { ...post, likeCount: state.likeCount, liked: state.liked }
329
- if (this.likers) this.likers = await galleryApi.likers(post.id)
341
+ if (this.showingLikers) this.likersRead.refetch()
330
342
  this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }))
331
343
  } catch (error) {
332
344
  notify({ level: 'error', message: reasonOf(error) })
@@ -335,16 +347,8 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
335
347
  }
336
348
  }
337
349
 
338
- private async showLikers() {
339
- if (this.likers) {
340
- this.likers = undefined
341
- return
342
- }
343
- try {
344
- this.likers = await galleryApi.likers(this.post.id)
345
- } catch (error) {
346
- notify({ level: 'error', message: reasonOf(error) })
347
- }
350
+ private showLikers() {
351
+ this.showingLikers = !this.showingLikers
348
352
  }
349
353
 
350
354
  private edit() {
@@ -82,12 +82,6 @@ export const galleryApi = {
82
82
  ),
83
83
  post: (id: string) =>
84
84
  ask<Post | null>(`query ($id: String!) { galleryPost(id: $id) { ${POST_FIELDS} } }`, { id }, 'galleryPost'),
85
- likers: (id: string) =>
86
- ask<{ id: string; name?: string }[]>(
87
- `query ($id: String!) { galleryLikers(id: $id) { id name } }`,
88
- { id },
89
- 'galleryLikers'
90
- ),
91
85
  tags: (text = '') =>
92
86
  ask<{ tag: string; count: number }[]>(
93
87
  `query ($text: String) { galleryTags(text: $text) { tag count } }`,
@@ -23,7 +23,8 @@ export declare class GalleryUploader extends GalleryUploader_base {
23
23
  private tagText;
24
24
  /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
25
25
  private tagRefusal;
26
- private suggestions;
26
+ /** The tag text the suggestions are for - the typed text once typing pauses. */
27
+ private suggestFor?;
27
28
  private chosenSpace;
28
29
  /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
29
30
  private shared;
@@ -36,6 +37,8 @@ export declare class GalleryUploader extends GalleryUploader_base {
36
37
  private picker;
37
38
  private camera;
38
39
  private suggestTimer?;
40
+ private suggestionsRead;
41
+ private get suggestions();
39
42
  render(): import("lit-html").TemplateResult<1>;
40
43
  private choiceChip;
41
44
  firstUpdated(): Promise<void>;
@@ -10,8 +10,10 @@ import '@material/web/icon/icon.js';
10
10
  import '@operato/input/ox-input-file.js';
11
11
  import '@operato/input/ox-input-select-buttons.js';
12
12
  import '@operato/popup/ox-popup-actions.js';
13
+ import gql from 'graphql-tag';
13
14
  import { css, html, LitElement, nothing } from 'lit';
14
15
  import { customElement, property, query, state } from 'lit/decorators.js';
16
+ import { QueryController } from '@operato/graphql';
15
17
  import { i18next, localize } from '@operato/i18n';
16
18
  import { notify } from '@operato/layout';
17
19
  import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles';
@@ -41,7 +43,6 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
41
43
  this.tagText = '';
42
44
  /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
43
45
  this.tagRefusal = '';
44
- this.suggestions = [];
45
46
  this.chosenSpace = 'COMPANY';
46
47
  /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
47
48
  this.shared = false;
@@ -50,6 +51,11 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
50
51
  this.choices = [];
51
52
  this.allChoices = false;
52
53
  this.busy = false;
54
+ /* The tags used before that begin like the one typed; the last ones stay while the next are read. */
55
+ this.suggestionsRead = new QueryController(this, gql `query ($text: String) { galleryTags(text: $text) { tag count } }`, {
56
+ variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),
57
+ keepPrevious: true
58
+ });
53
59
  }
54
60
  static { this.styles = [
55
61
  CommonPopupStyles,
@@ -217,6 +223,9 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
217
223
  }
218
224
  `
219
225
  ]; }
226
+ get suggestions() {
227
+ return this.suggestionsRead.data?.galleryTags ?? [];
228
+ }
220
229
  render() {
221
230
  const total = this.kept.length + this.added.length;
222
231
  const full = total >= MAX_PHOTOS;
@@ -464,14 +473,7 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
464
473
  }
465
474
  this.tagText = value;
466
475
  clearTimeout(this.suggestTimer);
467
- this.suggestTimer = setTimeout(async () => {
468
- try {
469
- this.suggestions = await galleryApi.tags(this.tagText);
470
- }
471
- catch {
472
- this.suggestions = [];
473
- }
474
- }, 200);
476
+ this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200);
475
477
  }
476
478
  tagKey(e) {
477
479
  if (e.isComposing)
@@ -575,8 +577,8 @@ __decorate([
575
577
  ], GalleryUploader.prototype, "tagRefusal", void 0);
576
578
  __decorate([
577
579
  state(),
578
- __metadata("design:type", Array)
579
- ], GalleryUploader.prototype, "suggestions", void 0);
580
+ __metadata("design:type", String)
581
+ ], GalleryUploader.prototype, "suggestFor", void 0);
580
582
  __decorate([
581
583
  state(),
582
584
  __metadata("design:type", String)
@@ -1 +1 @@
1
- {"version":3,"file":"gallery-uploader.js","sourceRoot":"","sources":["../../client/components/gallery-uploader.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Posting photos (ADR-0165 decision 3) - and changing one's own post. Photos are all it needs; the caption, the tags\n * and the event are there to add. When the photos were taken is read from the first one, and the events near that day\n * are offered first - one press puts the post on one.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-file.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport {\n galleryApi,\n galleryChanged,\n type EventChoice,\n type Photo,\n type Post,\n type Space\n} from '../utils/gallery-api.js'\nimport { day, reasonOf, t } from '../utils/gallery-words.js'\nimport { shrunk, takenAtOf } from '../utils/photo-prep.js'\n\nconst MAX_PHOTOS = 20\nconst MAX_CAPTION = 500\nconst MAX_TAGS = 10\nconst MAX_TAG = 30\n/* The events shown before 「more」 - the near ones are among them. */\nconst FIRST_CHOICES = 4\n\ntype Added = { file: File; url: string }\n\n/** yyyy-mm-dd of a date in the reader's own time. */\nconst dateText = (value: Date) =>\n `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`\n\n@customElement('gallery-uploader')\nexport class GalleryUploader extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n }\n h4 {\n margin: 0 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .photos {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));\n gap: var(--spacing-small, 4px);\n }\n .photo {\n position: relative;\n aspect-ratio: 1;\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n background: var(--md-sys-color-surface-container-high);\n }\n .photo img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n .photo button {\n position: absolute;\n top: 2px;\n inset-inline-end: 2px;\n display: inline-flex;\n padding: 2px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n cursor: pointer;\n }\n .photo button md-icon {\n --md-icon-size: 16px;\n }\n .add {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n aspect-ratio: 1;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline));\n border-radius: var(--border-radius, 4px);\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n }\n .add[disabled] {\n opacity: 0.4;\n cursor: default;\n }\n ox-input-file {\n display: contents;\n }\n textarea,\n input {\n box-sizing: border-box;\n width: 100%;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n textarea {\n min-height: 64px;\n resize: vertical;\n }\n input[type='date'] {\n width: auto;\n }\n .count {\n text-align: end;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .refusal {\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-error);\n }\n .chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n border-radius: 999px;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n line-height: 1.6;\n cursor: pointer;\n }\n .chip[aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .chip .near {\n color: var(--md-sys-color-primary);\n }\n .tag-input {\n flex: 1;\n min-width: 120px;\n width: auto;\n border: 0;\n padding: 2px 0;\n background: none;\n }\n .tag-input:focus {\n outline: none;\n }\n .tags {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n }\n .suggest {\n margin-top: var(--spacing-small, 4px);\n }\n .suggest .chip {\n border-style: dashed;\n }\n .muted {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-large, 12px);\n align-items: flex-end;\n }\n `\n ]\n\n /** The post being changed - nothing when posting a new one. */\n @property({ attribute: false }) post?: Post\n /** The photos the page picked before the window opened. */\n @property({ attribute: false }) files: File[] = []\n /** Where a new post goes - the screen it was opened from. */\n @property() space: Space = 'COMPANY'\n @property() eventId?: string | null\n\n @state() private added: Added[] = []\n @state() private kept: Photo[] = []\n @state() private caption = ''\n @state() private tags: string[] = []\n @state() private tagText = ''\n /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */\n @state() private tagRefusal = ''\n @state() private suggestions: { tag: string; count: number }[] = []\n @state() private chosenSpace: Space = 'COMPANY'\n /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */\n @state() private shared = false\n @state() private chosenEvent: string | null = null\n @state() private takenOn = dateText(new Date())\n @state() private choices: EventChoice[] = []\n @state() private allChoices = false\n @state() private progress?: number\n @state() private busy = false\n\n @query('#pick') private picker!: any\n @query('#shoot') private camera!: any\n\n private suggestTimer?: ReturnType<typeof setTimeout>\n\n render() {\n const total = this.kept.length + this.added.length\n const full = total >= MAX_PHOTOS\n const company = this.chosenSpace === 'COMPANY'\n const shown = this.allChoices ? this.choices : this.choices.slice(0, FIRST_CHOICES)\n const chosen = this.choices.find(one => one.id === this.chosenEvent)\n return html`<div class=\"body\">\n <section>\n <div class=\"photos\">\n ${this.kept.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.thumbnail || one.fullpath} alt=\"\" />\n <button\n aria-label=${t('gallery.button.remove-photo')}\n @click=${() => (this.kept = this.kept.filter(other => other !== one))}\n >\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n ${this.added.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.url} alt=\"\" />\n <button aria-label=${t('gallery.button.remove-photo')} @click=${() => this.drop(one)}>\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n <button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.picker?.pick()}>\n <md-icon>add_photo_alternate</md-icon>${t('gallery.button.add-photos')}\n </button>\n ${\n isMobileDevice()\n ? html`<button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.camera?.pick()}>\n <md-icon>photo_camera</md-icon>${t('gallery.button.shoot-more')}\n </button>`\n : nothing\n }\n </div>\n <ox-input-file\n id=\"pick\"\n quiet\n outside-trigger\n hide-filelist\n multiple\n accept=\"image/*\"\n .progress=${this.progress}\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n <ox-input-file\n id=\"shoot\"\n quiet\n outside-trigger\n hide-filelist\n accept=\"image/*\"\n capture=\"environment\"\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n ${full ? html`<div class=\"muted\">${t('gallery.text.photos-full', { count: MAX_PHOTOS })}</div>` : nothing}\n </section>\n\n <section>\n <textarea\n maxlength=${MAX_CAPTION}\n placeholder=${t('gallery.text.caption-placeholder')}\n .value=${this.caption}\n @input=${(e: any) => (this.caption = e.target.value)}\n ></textarea>\n ${this.caption.length > MAX_CAPTION * 0.8 ? html`<div class=\"count\">${this.caption.length} / ${MAX_CAPTION}</div>` : nothing}\n </section>\n\n <section>\n <h4>${t('gallery.field.tags')}</h4>\n <div class=\"chips tags\">\n ${this.tags.map(tag => html`<span class=\"chip\">#${tag}<md-icon role=\"button\" aria-label=${t('gallery.button.remove-tag')} @click=${() => (this.tags = this.tags.filter(one => one !== tag))}>close</md-icon></span>`)}\n ${\n this.tags.length < MAX_TAGS\n ? html`<input\n class=\"tag-input\"\n .value=${this.tagText}\n placeholder=${this.tags.length ? '' : t('gallery.text.tag-placeholder')}\n @input=${(e: any) => this.typeTag(e.target.value)}\n @keydown=${(e: KeyboardEvent) => this.tagKey(e)}\n @blur=${() => this.addTag(this.tagText)}\n />`\n : nothing\n }\n </div>\n ${this.tagRefusal ? html`<div class=\"refusal\" role=\"alert\">${this.tagRefusal}</div>` : nothing}\n ${\n this.suggestions.length\n ? html`<div class=\"chips suggest\">\n ${this.suggestions.filter(one => !this.tags.some(tag => tag.toLowerCase() === one.tag.toLowerCase())).map(one => html`<button class=\"chip\" @mousedown=${(e: Event) => e.preventDefault()} @click=${() => this.addTag(one.tag)}>#${one.tag}</button>`)}\n </div>`\n : nothing\n }\n </section>\n\n <section class=\"row\">\n <div>\n <h4>${t('gallery.field.space')}</h4>\n <ox-input-select-buttons\n .options=${(['COMPANY', 'PERSONAL'] as Space[]).map(space => ({ value: space, display: t(`gallery.space.${space}`) }))}\n .value=${this.chosenSpace}\n @change=${(e: CustomEvent) => (e.detail ? this.chooseSpace(e.detail as Space) : ((e.target as any).value = this.chosenSpace))}\n ></ox-input-select-buttons>\n </div>\n <div>\n <h4>${t('gallery.field.taken-on')}</h4>\n <input type=\"date\" .value=${this.takenOn} @change=${(e: any) => this.changeDay(e.target.value)} />\n </div>\n </section>\n\n ${\n company\n ? html`<section>\n <h4>${t('gallery.field.event')}</h4>\n <div class=\"chips\">\n <button\n class=\"chip\"\n aria-pressed=${String(!this.chosenEvent)}\n @click=${() => (this.chosenEvent = null)}\n >\n ${t('gallery.text.no-event')}\n </button>\n ${chosen && !shown.includes(chosen) ? this.choiceChip(chosen) : nothing}\n ${shown.map(one => this.choiceChip(one))}\n ${\n this.choices.length > FIRST_CHOICES && !this.allChoices\n ? html`<button class=\"chip\" @click=${() => (this.allChoices = true)}>\n ${t('gallery.button.more-events', { count: this.choices.length - FIRST_CHOICES })}\n </button>`\n : nothing\n }\n </div>\n </section>`\n : html`<section>\n <h4>${t('gallery.field.shared')}</h4>\n <ox-input-select-buttons\n .options=${[\n { value: 'me', display: t('gallery.text.only-me') },\n { value: 'everyone', display: t('gallery.text.everyone') }\n ]}\n .value=${this.shared ? 'everyone' : 'me'}\n @change=${(e: CustomEvent) => (e.detail ? (this.shared = e.detail === 'everyone') : ((e.target as any).value = this.shared ? 'everyone' : 'me'))}\n ></ox-input-select-buttons>\n <div class=\"muted\">${t(this.shared ? 'gallery.text.shared-note' : 'gallery.text.only-me-note')}</div>\n </section>`\n }\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" ?disabled=${this.busy} @click=${() => this.close()}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || total < 1} @click=${() => this.save()}\n >${this.post ? t('gallery.button.save') : t('gallery.button.post-count', { count: total })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private choiceChip(one: EventChoice) {\n return html`<button\n class=\"chip\"\n aria-pressed=${String(this.chosenEvent === one.id)}\n @click=${() => (this.chosenEvent = one.id)}\n >\n ${one.near ? html`<md-icon class=\"near\">event_available</md-icon>` : nothing}${one.name}<span class=\"muted\"\n >· ${day(one.startAt)}</span\n >\n </button>`\n }\n\n async firstUpdated() {\n const post = this.post\n if (post) {\n this.kept = [...post.photos]\n this.caption = post.caption ?? ''\n this.tags = [...(post.tags ?? [])]\n this.chosenSpace = post.space\n this.shared = post.shared\n this.chosenEvent = post.event?.id ?? null\n this.takenOn = dateText(new Date(post.takenAt))\n } else {\n this.chosenSpace = this.eventId ? 'COMPANY' : this.space\n this.chosenEvent = this.eventId ?? null\n }\n await this.add(this.files ?? [])\n await this.loadChoices()\n }\n\n disconnectedCallback() {\n for (const one of this.added) URL.revokeObjectURL(one.url)\n clearTimeout(this.suggestTimer)\n super.disconnectedCallback()\n }\n\n private async take(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n const before = this.kept.length + this.added.length\n await this.add(picked)\n /* The first photo says the day - the events near it come first. */\n if (!before && !this.post) await this.loadChoices()\n }\n\n private async add(files: File[]) {\n const room = MAX_PHOTOS - this.kept.length - this.added.length\n const photos = files\n .filter(file => /^image\\//i.test(file.type) || /\\.(jpe?g|png|gif|webp|heic|heif)$/i.test(file.name))\n .slice(0, Math.max(0, room))\n if (photos.length < files.length)\n notify({ level: 'warn', message: t('gallery.text.photos-skipped', { count: files.length - photos.length }) })\n if (!photos.length) return\n const first = !this.kept.length && !this.added.length && !this.post\n this.added = [...this.added, ...photos.map(file => ({ file, url: URL.createObjectURL(file) }))]\n if (first) {\n const takenAt = await takenAtOf(photos[0])\n if (takenAt) this.takenOn = dateText(takenAt)\n }\n }\n\n private drop(one: Added) {\n URL.revokeObjectURL(one.url)\n this.added = this.added.filter(other => other !== one)\n }\n\n private takenAt(): string {\n const [y, m, d] = this.takenOn.split('-').map(Number)\n const now = new Date()\n /* A day chosen without its hour keeps the hour it was posted - today's photo is not dated midnight. */\n const at = y ? new Date(y, m - 1, d, now.getHours(), now.getMinutes()) : now\n return at.toISOString()\n }\n\n private async loadChoices() {\n try {\n /* Offered, not chosen: the events near that day come first, and one press puts the post on one. */\n this.choices = await galleryApi.eventChoices(this.takenAt())\n } catch {\n this.choices = []\n }\n }\n\n private async changeDay(value: string) {\n if (!value) return\n this.takenOn = value\n await this.loadChoices()\n }\n\n private chooseSpace(space: Space) {\n this.chosenSpace = space\n if (space === 'PERSONAL') this.chosenEvent = null\n }\n\n private typeTag(value: string) {\n if (/[,\\s]$/.test(value) && value.trim()) {\n this.addTag(value)\n return\n }\n this.tagText = value\n clearTimeout(this.suggestTimer)\n this.suggestTimer = setTimeout(async () => {\n try {\n this.suggestions = await galleryApi.tags(this.tagText)\n } catch {\n this.suggestions = []\n }\n }, 200)\n }\n\n private tagKey(e: KeyboardEvent) {\n if (e.isComposing) return\n if (e.key === 'Enter') {\n e.preventDefault()\n this.addTag(this.tagText)\n } else if (e.key === 'Backspace' && !this.tagText && this.tags.length) {\n this.tags = this.tags.slice(0, -1)\n }\n }\n\n /** Takes the typed tag, or says why not and keeps it - a longer tag was cut at 30 without a word (2026-10-30). */\n private addTag(raw: string): boolean {\n const tag = raw.replace(/[,]/g, ' ').trim().replace(/^#+/, '').replace(/\\s+/g, ' ').trim()\n if (tag.length > MAX_TAG) {\n this.tagRefusal = t('gallery.text.tag-too-long-typed', { max: MAX_TAG, length: tag.length })\n return false\n }\n this.tagRefusal = ''\n this.tagText = ''\n if (!tag || this.tags.length >= MAX_TAGS || this.tags.some(one => one.toLowerCase() === tag.toLowerCase())) return true\n this.tags = [...this.tags, tag]\n return true\n }\n\n private async save() {\n if (!this.addTag(this.tagText)) return\n this.busy = true\n try {\n const files = await Promise.all(this.added.map(one => shrunk(one.file)))\n const input = {\n space: this.chosenSpace,\n shared: this.chosenSpace === 'PERSONAL' && this.shared,\n caption: this.caption.trim(),\n takenAt: this.takenAt(),\n tags: this.tags,\n eventId: this.chosenSpace === 'COMPANY' ? this.chosenEvent : null\n }\n const uploading = (fraction: number) => (this.progress = fraction)\n const post = this.post\n ? await galleryApi.update(\n this.post.id,\n input,\n files,\n this.post.photos.filter(one => !this.kept.includes(one)).map(one => one.id),\n uploading\n )\n : await galleryApi.create(input, files, uploading)\n notify({ message: this.post ? t('gallery.text.saved') : t('gallery.text.posted') })\n galleryChanged()\n this.dispatchEvent(new CustomEvent('gallery-posted', { detail: post, bubbles: true, composed: true }))\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.progress = undefined\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"gallery-uploader.js","sourceRoot":"","sources":["../../client/components/gallery-uploader.ts"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,uCAAuC,CAAA;AAC9C,OAAO,qCAAqC,CAAA;AAC5C,OAAO,4BAA4B,CAAA;AACnC,OAAO,iCAAiC,CAAA;AACxC,OAAO,2CAA2C,CAAA;AAClD,OAAO,oCAAoC,CAAA;AAE3C,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EACL,UAAU,EACV,cAAc,EAKf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAE1D,MAAM,UAAU,GAAG,EAAE,CAAA;AACrB,MAAM,WAAW,GAAG,GAAG,CAAA;AACvB,MAAM,QAAQ,GAAG,EAAE,CAAA;AACnB,MAAM,OAAO,GAAG,EAAE,CAAA;AAClB,oEAAoE;AACpE,MAAM,aAAa,GAAG,CAAC,CAAA;AAIvB,qDAAqD;AACrD,MAAM,QAAQ,GAAG,CAAC,KAAW,EAAE,EAAE,CAC/B,GAAG,KAAK,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AAGhH,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA3D;;QA0KL,2DAA2D;QAC3B,UAAK,GAAW,EAAE,CAAA;QAClD,6DAA6D;QACjD,UAAK,GAAU,SAAS,CAAA;QAGnB,UAAK,GAAY,EAAE,CAAA;QACnB,SAAI,GAAY,EAAE,CAAA;QAClB,YAAO,GAAG,EAAE,CAAA;QACZ,SAAI,GAAa,EAAE,CAAA;QACnB,YAAO,GAAG,EAAE,CAAA;QAC7B,yGAAyG;QACxF,eAAU,GAAG,EAAE,CAAA;QAGf,gBAAW,GAAU,SAAS,CAAA;QAC/C,oGAAoG;QACnF,WAAM,GAAG,KAAK,CAAA;QACd,gBAAW,GAAkB,IAAI,CAAA;QACjC,YAAO,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QAC9B,YAAO,GAAkB,EAAE,CAAA;QAC3B,eAAU,GAAG,KAAK,CAAA;QAElB,SAAI,GAAG,KAAK,CAAA;QAO7B,qGAAqG;QAC7F,oBAAe,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAA,kEAAkE,EAAE;YACzH,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YACxF,YAAY,EAAE,IAAI;SACnB,CAAC,CAAA;IAgVJ,CAAC;aA3hBQ,WAAM,GAAG;QACd,iBAAiB;QACjB,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiKF;KACF,AArKY,CAqKZ;IAwCD,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAA;IACrD,CAAC;IAED,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;QAClD,MAAM,IAAI,GAAG,KAAK,IAAI,UAAU,CAAA;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,SAAS,CAAA;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAA;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,WAAW,CAAC,CAAA;QACpE,OAAO,IAAI,CAAA;;;cAGD,IAAI,CAAC,IAAI,CAAC,GAAG,CACb,GAAG,CAAC,EAAE,CACJ,IAAI,CAAA;6BACS,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ;;iCAEzB,CAAC,CAAC,6BAA6B,CAAC;6BACpC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;;;;uBAIlE,CACV;cACC,IAAI,CAAC,KAAK,CAAC,GAAG,CACd,GAAG,CAAC,EAAE,CACJ,IAAI,CAAA;6BACS,GAAG,CAAC,GAAG;uCACG,CAAC,CAAC,6BAA6B,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;;;uBAG/E,CACV;4CAC+B,IAAI,IAAI,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;sDAC3C,CAAC,CAAC,2BAA2B,CAAC;;cAGtE,cAAc,EAAE;YACd,CAAC,CAAC,IAAI,CAAA,iCAAiC,IAAI,IAAI,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;qDACvD,CAAC,CAAC,2BAA2B,CAAC;4BACvD;YACZ,CAAC,CAAC,OACN;;;;;;;;;wBASY,IAAI,CAAC,QAAQ;sBACf,CAAC,CAAc,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;;;;;;;;sBAShC,CAAC,CAAc,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;YAE1C,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,sBAAsB,CAAC,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;;;;;wBAK3F,WAAW;0BACT,CAAC,CAAC,kCAAkC,CAAC;qBAC1C,IAAI,CAAC,OAAO;qBACZ,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;YAEpD,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA,sBAAsB,IAAI,CAAC,OAAO,CAAC,MAAM,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAC,OAAO;;;;gBAItH,CAAC,CAAC,oBAAoB,CAAC;;cAEzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,uBAAuB,GAAG,qCAAqC,CAAC,CAAC,2BAA2B,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,yBAAyB,CAAC;cAEnN,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ;YACzB,CAAC,CAAC,IAAI,CAAA;;6BAEO,IAAI,CAAC,OAAO;kCACP,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC;6BAC9D,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;+BACtC,CAAC,CAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;4BACvC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;qBACtC;YACL,CAAC,CAAC,OACN;;YAEA,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA,qCAAqC,IAAI,CAAC,UAAU,QAAQ,CAAC,CAAC,CAAC,OAAO;YAE5F,IAAI,CAAC,WAAW,CAAC,MAAM;YACrB,CAAC,CAAC,IAAI,CAAA;oBACA,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,mCAAmC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,WAAW,CAAC;uBAChP;YACT,CAAC,CAAC,OACN;;;;;kBAKQ,CAAC,CAAC,qBAAqB,CAAC;;yBAEhB,CAAC,SAAS,EAAE,UAAU,CAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,iBAAiB,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;uBAC7G,IAAI,CAAC,WAAW;wBACf,CAAC,CAAc,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAe,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,MAAc,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;;;;kBAIzH,CAAC,CAAC,wBAAwB,CAAC;wCACL,IAAI,CAAC,OAAO,YAAY,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;;;UAKhG,OAAO;YACL,CAAC,CAAC,IAAI,CAAA;sBACI,CAAC,CAAC,qBAAqB,CAAC;;;;mCAIX,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;6BAC/B,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;sBAEtC,CAAC,CAAC,uBAAuB,CAAC;;oBAE5B,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO;oBACrE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;oBAEtC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,aAAa,IAAI,CAAC,IAAI,CAAC,UAAU;gBACrD,CAAC,CAAC,IAAI,CAAA,+BAA+B,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;4BAC7D,CAAC,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;kCACzE;gBACZ,CAAC,CAAC,OACN;;yBAEO;YACb,CAAC,CAAC,IAAI,CAAA;sBACI,CAAC,CAAC,sBAAsB,CAAC;;6BAElB;gBACT,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE;gBACnD,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,uBAAuB,CAAC,EAAE;aAC3D;2BACQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;4BAC9B,CAAC,CAAc,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,MAAc,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;;qCAE7H,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,2BAA2B,CAAC;yBAEtG;;;kDAG0C,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE;aAC3E,CAAC,CAAC,uBAAuB,CAAC;;qDAEc,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;aAC1F,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;;0BAE1E,CAAA;IACxB,CAAC;IAEO,UAAU,CAAC,GAAgB;QACjC,OAAO,IAAI,CAAA;;qBAEM,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,GAAG,CAAC,EAAE,CAAC;eACzC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,EAAE,CAAC;;QAExC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,iDAAiD,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI;aAChF,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;;cAEf,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;YAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA;YACjC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAA;YAClC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAA;YAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;YACzB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,CAAA;YACzC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;QACjD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAA;YACxD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAA;QACzC,CAAC;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;QAChC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;IAC1B,CAAC;IAED,oBAAoB;QAClB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK;YAAE,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC1D,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAC/B,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,CAAc;QAC/B,MAAM,MAAM,GAAG,CAAC,GAAG,CAAE,CAAC,CAAC,MAAiB,IAAI,EAAE,CAAC,CAAC,CAAA;QAChD,oFAAoF;QACpF,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OACnB;QAAC,CAAC,CAAC,MAAc,CAAC,KAAK,EAAE,EAAE,CAAA;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;QACnD,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACtB,mEAAmE;QACnE,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;IACrD,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,KAAa;QAC7B,MAAM,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;QAC9D,MAAM,MAAM,GAAG,KAAK;aACjB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACnG,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;QAC9B,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;YAC9B,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;QAC/G,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAM;QAC1B,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;QACnE,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC/F,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1C,IAAI,OAAO;gBAAE,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC/C,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,GAAU;QACrB,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAAA;IACxD,CAAC;IAEO,OAAO;QACb,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACrD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,uGAAuG;QACvG,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAC5E,OAAO,EAAE,CAAC,WAAW,EAAE,CAAA;IACzB,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC;YACH,mGAAmG;YACnG,IAAI,CAAC,OAAO,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,KAAa;QACnC,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;IAC1B,CAAC;IAEO,WAAW,CAAC,KAAY;QAC9B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QACxB,IAAI,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;IACnD,CAAC;IAEO,OAAO,CAAC,KAAa;QAC3B,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAC/B,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAA;IAC7E,CAAC;IAEO,MAAM,CAAC,CAAgB;QAC7B,IAAI,CAAC,CAAC,WAAW;YAAE,OAAM;QACzB,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACtB,CAAC,CAAC,cAAc,EAAE,CAAA;YAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC3B,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACpC,CAAC;IACH,CAAC;IAED,kHAAkH;IAC1G,MAAM,CAAC,GAAW;QACxB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QAC1F,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,iCAAiC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;YAC5F,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,IAAI,CAAA;QACvH,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAM;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACxE,MAAM,KAAK,GAAG;gBACZ,KAAK,EAAE,IAAI,CAAC,WAAW;gBACvB,MAAM,EAAE,IAAI,CAAC,WAAW,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM;gBACtD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;aAClE,CAAA;YACD,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAA;YAClE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;gBACpB,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,CACrB,IAAI,CAAC,IAAI,CAAC,EAAE,EACZ,KAAK,EACL,KAAK,EACL,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAC3E,SAAS,CACV;gBACH,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAA;YACpD,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAA;YACnF,cAAc,EAAE,CAAA;YAChB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACtG,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;YACzB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAChF,CAAC;;AAlX+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;6CAAY;AAEX;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;8CAAmB;AAEtC;IAAX,QAAQ,EAAE;;8CAAyB;AACxB;IAAX,QAAQ,EAAE;;gDAAwB;AAElB;IAAhB,KAAK,EAAE;;8CAA4B;AACnB;IAAhB,KAAK,EAAE;;6CAA2B;AAClB;IAAhB,KAAK,EAAE;;gDAAqB;AACZ;IAAhB,KAAK,EAAE;;6CAA4B;AACnB;IAAhB,KAAK,EAAE;;gDAAqB;AAEZ;IAAhB,KAAK,EAAE;;mDAAwB;AAEf;IAAhB,KAAK,EAAE;;mDAA4B;AACnB;IAAhB,KAAK,EAAE;;oDAAuC;AAE9B;IAAhB,KAAK,EAAE;;+CAAuB;AACd;IAAhB,KAAK,EAAE;;oDAA0C;AACjC;IAAhB,KAAK,EAAE;;gDAAuC;AAC9B;IAAhB,KAAK,EAAE;;gDAAoC;AAC3B;IAAhB,KAAK,EAAE;;mDAA2B;AAClB;IAAhB,KAAK,EAAE;;iDAA0B;AACjB;IAAhB,KAAK,EAAE;;6CAAqB;AAEL;IAAvB,KAAK,CAAC,OAAO,CAAC;;+CAAqB;AACX;IAAxB,KAAK,CAAC,QAAQ,CAAC;;+CAAqB;AApM1B,eAAe;IAD3B,aAAa,CAAC,kBAAkB,CAAC;GACrB,eAAe,CA4hB3B","sourcesContent":["/*\n * Posting photos (ADR-0165 decision 3) - and changing one's own post. Photos are all it needs; the caption, the tags\n * and the event are there to add. When the photos were taken is read from the first one, and the events near that day\n * are offered first - one press puts the post on one.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-file.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport {\n galleryApi,\n galleryChanged,\n type EventChoice,\n type Photo,\n type Post,\n type Space\n} from '../utils/gallery-api.js'\nimport { day, reasonOf, t } from '../utils/gallery-words.js'\nimport { shrunk, takenAtOf } from '../utils/photo-prep.js'\n\nconst MAX_PHOTOS = 20\nconst MAX_CAPTION = 500\nconst MAX_TAGS = 10\nconst MAX_TAG = 30\n/* The events shown before 「more」 - the near ones are among them. */\nconst FIRST_CHOICES = 4\n\ntype Added = { file: File; url: string }\n\n/** yyyy-mm-dd of a date in the reader's own time. */\nconst dateText = (value: Date) =>\n `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`\n\n@customElement('gallery-uploader')\nexport class GalleryUploader extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n }\n h4 {\n margin: 0 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .photos {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));\n gap: var(--spacing-small, 4px);\n }\n .photo {\n position: relative;\n aspect-ratio: 1;\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n background: var(--md-sys-color-surface-container-high);\n }\n .photo img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n .photo button {\n position: absolute;\n top: 2px;\n inset-inline-end: 2px;\n display: inline-flex;\n padding: 2px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n cursor: pointer;\n }\n .photo button md-icon {\n --md-icon-size: 16px;\n }\n .add {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n aspect-ratio: 1;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline));\n border-radius: var(--border-radius, 4px);\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n }\n .add[disabled] {\n opacity: 0.4;\n cursor: default;\n }\n ox-input-file {\n display: contents;\n }\n textarea,\n input {\n box-sizing: border-box;\n width: 100%;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n textarea {\n min-height: 64px;\n resize: vertical;\n }\n input[type='date'] {\n width: auto;\n }\n .count {\n text-align: end;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .refusal {\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-error);\n }\n .chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n border-radius: 999px;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n line-height: 1.6;\n cursor: pointer;\n }\n .chip[aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .chip .near {\n color: var(--md-sys-color-primary);\n }\n .tag-input {\n flex: 1;\n min-width: 120px;\n width: auto;\n border: 0;\n padding: 2px 0;\n background: none;\n }\n .tag-input:focus {\n outline: none;\n }\n .tags {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n }\n .suggest {\n margin-top: var(--spacing-small, 4px);\n }\n .suggest .chip {\n border-style: dashed;\n }\n .muted {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-large, 12px);\n align-items: flex-end;\n }\n `\n ]\n\n /** The post being changed - nothing when posting a new one. */\n @property({ attribute: false }) post?: Post\n /** The photos the page picked before the window opened. */\n @property({ attribute: false }) files: File[] = []\n /** Where a new post goes - the screen it was opened from. */\n @property() space: Space = 'COMPANY'\n @property() eventId?: string | null\n\n @state() private added: Added[] = []\n @state() private kept: Photo[] = []\n @state() private caption = ''\n @state() private tags: string[] = []\n @state() private tagText = ''\n /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */\n @state() private tagRefusal = ''\n /** The tag text the suggestions are for - the typed text once typing pauses. */\n @state() private suggestFor?: string\n @state() private chosenSpace: Space = 'COMPANY'\n /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */\n @state() private shared = false\n @state() private chosenEvent: string | null = null\n @state() private takenOn = dateText(new Date())\n @state() private choices: EventChoice[] = []\n @state() private allChoices = false\n @state() private progress?: number\n @state() private busy = false\n\n @query('#pick') private picker!: any\n @query('#shoot') private camera!: any\n\n private suggestTimer?: ReturnType<typeof setTimeout>\n\n /* The tags used before that begin like the one typed; the last ones stay while the next are read. */\n private suggestionsRead = new QueryController(this, gql`query ($text: String) { galleryTags(text: $text) { tag count } }`, {\n variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),\n keepPrevious: true\n })\n\n private get suggestions(): { tag: string; count: number }[] {\n return this.suggestionsRead.data?.galleryTags ?? []\n }\n\n render() {\n const total = this.kept.length + this.added.length\n const full = total >= MAX_PHOTOS\n const company = this.chosenSpace === 'COMPANY'\n const shown = this.allChoices ? this.choices : this.choices.slice(0, FIRST_CHOICES)\n const chosen = this.choices.find(one => one.id === this.chosenEvent)\n return html`<div class=\"body\">\n <section>\n <div class=\"photos\">\n ${this.kept.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.thumbnail || one.fullpath} alt=\"\" />\n <button\n aria-label=${t('gallery.button.remove-photo')}\n @click=${() => (this.kept = this.kept.filter(other => other !== one))}\n >\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n ${this.added.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.url} alt=\"\" />\n <button aria-label=${t('gallery.button.remove-photo')} @click=${() => this.drop(one)}>\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n <button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.picker?.pick()}>\n <md-icon>add_photo_alternate</md-icon>${t('gallery.button.add-photos')}\n </button>\n ${\n isMobileDevice()\n ? html`<button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.camera?.pick()}>\n <md-icon>photo_camera</md-icon>${t('gallery.button.shoot-more')}\n </button>`\n : nothing\n }\n </div>\n <ox-input-file\n id=\"pick\"\n quiet\n outside-trigger\n hide-filelist\n multiple\n accept=\"image/*\"\n .progress=${this.progress}\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n <ox-input-file\n id=\"shoot\"\n quiet\n outside-trigger\n hide-filelist\n accept=\"image/*\"\n capture=\"environment\"\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n ${full ? html`<div class=\"muted\">${t('gallery.text.photos-full', { count: MAX_PHOTOS })}</div>` : nothing}\n </section>\n\n <section>\n <textarea\n maxlength=${MAX_CAPTION}\n placeholder=${t('gallery.text.caption-placeholder')}\n .value=${this.caption}\n @input=${(e: any) => (this.caption = e.target.value)}\n ></textarea>\n ${this.caption.length > MAX_CAPTION * 0.8 ? html`<div class=\"count\">${this.caption.length} / ${MAX_CAPTION}</div>` : nothing}\n </section>\n\n <section>\n <h4>${t('gallery.field.tags')}</h4>\n <div class=\"chips tags\">\n ${this.tags.map(tag => html`<span class=\"chip\">#${tag}<md-icon role=\"button\" aria-label=${t('gallery.button.remove-tag')} @click=${() => (this.tags = this.tags.filter(one => one !== tag))}>close</md-icon></span>`)}\n ${\n this.tags.length < MAX_TAGS\n ? html`<input\n class=\"tag-input\"\n .value=${this.tagText}\n placeholder=${this.tags.length ? '' : t('gallery.text.tag-placeholder')}\n @input=${(e: any) => this.typeTag(e.target.value)}\n @keydown=${(e: KeyboardEvent) => this.tagKey(e)}\n @blur=${() => this.addTag(this.tagText)}\n />`\n : nothing\n }\n </div>\n ${this.tagRefusal ? html`<div class=\"refusal\" role=\"alert\">${this.tagRefusal}</div>` : nothing}\n ${\n this.suggestions.length\n ? html`<div class=\"chips suggest\">\n ${this.suggestions.filter(one => !this.tags.some(tag => tag.toLowerCase() === one.tag.toLowerCase())).map(one => html`<button class=\"chip\" @mousedown=${(e: Event) => e.preventDefault()} @click=${() => this.addTag(one.tag)}>#${one.tag}</button>`)}\n </div>`\n : nothing\n }\n </section>\n\n <section class=\"row\">\n <div>\n <h4>${t('gallery.field.space')}</h4>\n <ox-input-select-buttons\n .options=${(['COMPANY', 'PERSONAL'] as Space[]).map(space => ({ value: space, display: t(`gallery.space.${space}`) }))}\n .value=${this.chosenSpace}\n @change=${(e: CustomEvent) => (e.detail ? this.chooseSpace(e.detail as Space) : ((e.target as any).value = this.chosenSpace))}\n ></ox-input-select-buttons>\n </div>\n <div>\n <h4>${t('gallery.field.taken-on')}</h4>\n <input type=\"date\" .value=${this.takenOn} @change=${(e: any) => this.changeDay(e.target.value)} />\n </div>\n </section>\n\n ${\n company\n ? html`<section>\n <h4>${t('gallery.field.event')}</h4>\n <div class=\"chips\">\n <button\n class=\"chip\"\n aria-pressed=${String(!this.chosenEvent)}\n @click=${() => (this.chosenEvent = null)}\n >\n ${t('gallery.text.no-event')}\n </button>\n ${chosen && !shown.includes(chosen) ? this.choiceChip(chosen) : nothing}\n ${shown.map(one => this.choiceChip(one))}\n ${\n this.choices.length > FIRST_CHOICES && !this.allChoices\n ? html`<button class=\"chip\" @click=${() => (this.allChoices = true)}>\n ${t('gallery.button.more-events', { count: this.choices.length - FIRST_CHOICES })}\n </button>`\n : nothing\n }\n </div>\n </section>`\n : html`<section>\n <h4>${t('gallery.field.shared')}</h4>\n <ox-input-select-buttons\n .options=${[\n { value: 'me', display: t('gallery.text.only-me') },\n { value: 'everyone', display: t('gallery.text.everyone') }\n ]}\n .value=${this.shared ? 'everyone' : 'me'}\n @change=${(e: CustomEvent) => (e.detail ? (this.shared = e.detail === 'everyone') : ((e.target as any).value = this.shared ? 'everyone' : 'me'))}\n ></ox-input-select-buttons>\n <div class=\"muted\">${t(this.shared ? 'gallery.text.shared-note' : 'gallery.text.only-me-note')}</div>\n </section>`\n }\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" ?disabled=${this.busy} @click=${() => this.close()}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || total < 1} @click=${() => this.save()}\n >${this.post ? t('gallery.button.save') : t('gallery.button.post-count', { count: total })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private choiceChip(one: EventChoice) {\n return html`<button\n class=\"chip\"\n aria-pressed=${String(this.chosenEvent === one.id)}\n @click=${() => (this.chosenEvent = one.id)}\n >\n ${one.near ? html`<md-icon class=\"near\">event_available</md-icon>` : nothing}${one.name}<span class=\"muted\"\n >· ${day(one.startAt)}</span\n >\n </button>`\n }\n\n async firstUpdated() {\n const post = this.post\n if (post) {\n this.kept = [...post.photos]\n this.caption = post.caption ?? ''\n this.tags = [...(post.tags ?? [])]\n this.chosenSpace = post.space\n this.shared = post.shared\n this.chosenEvent = post.event?.id ?? null\n this.takenOn = dateText(new Date(post.takenAt))\n } else {\n this.chosenSpace = this.eventId ? 'COMPANY' : this.space\n this.chosenEvent = this.eventId ?? null\n }\n await this.add(this.files ?? [])\n await this.loadChoices()\n }\n\n disconnectedCallback() {\n for (const one of this.added) URL.revokeObjectURL(one.url)\n clearTimeout(this.suggestTimer)\n super.disconnectedCallback()\n }\n\n private async take(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n const before = this.kept.length + this.added.length\n await this.add(picked)\n /* The first photo says the day - the events near it come first. */\n if (!before && !this.post) await this.loadChoices()\n }\n\n private async add(files: File[]) {\n const room = MAX_PHOTOS - this.kept.length - this.added.length\n const photos = files\n .filter(file => /^image\\//i.test(file.type) || /\\.(jpe?g|png|gif|webp|heic|heif)$/i.test(file.name))\n .slice(0, Math.max(0, room))\n if (photos.length < files.length)\n notify({ level: 'warn', message: t('gallery.text.photos-skipped', { count: files.length - photos.length }) })\n if (!photos.length) return\n const first = !this.kept.length && !this.added.length && !this.post\n this.added = [...this.added, ...photos.map(file => ({ file, url: URL.createObjectURL(file) }))]\n if (first) {\n const takenAt = await takenAtOf(photos[0])\n if (takenAt) this.takenOn = dateText(takenAt)\n }\n }\n\n private drop(one: Added) {\n URL.revokeObjectURL(one.url)\n this.added = this.added.filter(other => other !== one)\n }\n\n private takenAt(): string {\n const [y, m, d] = this.takenOn.split('-').map(Number)\n const now = new Date()\n /* A day chosen without its hour keeps the hour it was posted - today's photo is not dated midnight. */\n const at = y ? new Date(y, m - 1, d, now.getHours(), now.getMinutes()) : now\n return at.toISOString()\n }\n\n private async loadChoices() {\n try {\n /* Offered, not chosen: the events near that day come first, and one press puts the post on one. */\n this.choices = await galleryApi.eventChoices(this.takenAt())\n } catch {\n this.choices = []\n }\n }\n\n private async changeDay(value: string) {\n if (!value) return\n this.takenOn = value\n await this.loadChoices()\n }\n\n private chooseSpace(space: Space) {\n this.chosenSpace = space\n if (space === 'PERSONAL') this.chosenEvent = null\n }\n\n private typeTag(value: string) {\n if (/[,\\s]$/.test(value) && value.trim()) {\n this.addTag(value)\n return\n }\n this.tagText = value\n clearTimeout(this.suggestTimer)\n this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200)\n }\n\n private tagKey(e: KeyboardEvent) {\n if (e.isComposing) return\n if (e.key === 'Enter') {\n e.preventDefault()\n this.addTag(this.tagText)\n } else if (e.key === 'Backspace' && !this.tagText && this.tags.length) {\n this.tags = this.tags.slice(0, -1)\n }\n }\n\n /** Takes the typed tag, or says why not and keeps it - a longer tag was cut at 30 without a word (2026-10-30). */\n private addTag(raw: string): boolean {\n const tag = raw.replace(/[,]/g, ' ').trim().replace(/^#+/, '').replace(/\\s+/g, ' ').trim()\n if (tag.length > MAX_TAG) {\n this.tagRefusal = t('gallery.text.tag-too-long-typed', { max: MAX_TAG, length: tag.length })\n return false\n }\n this.tagRefusal = ''\n this.tagText = ''\n if (!tag || this.tags.length >= MAX_TAGS || this.tags.some(one => one.toLowerCase() === tag.toLowerCase())) return true\n this.tags = [...this.tags, tag]\n return true\n }\n\n private async save() {\n if (!this.addTag(this.tagText)) return\n this.busy = true\n try {\n const files = await Promise.all(this.added.map(one => shrunk(one.file)))\n const input = {\n space: this.chosenSpace,\n shared: this.chosenSpace === 'PERSONAL' && this.shared,\n caption: this.caption.trim(),\n takenAt: this.takenAt(),\n tags: this.tags,\n eventId: this.chosenSpace === 'COMPANY' ? this.chosenEvent : null\n }\n const uploading = (fraction: number) => (this.progress = fraction)\n const post = this.post\n ? await galleryApi.update(\n this.post.id,\n input,\n files,\n this.post.photos.filter(one => !this.kept.includes(one)).map(one => one.id),\n uploading\n )\n : await galleryApi.create(input, files, uploading)\n notify({ message: this.post ? t('gallery.text.saved') : t('gallery.text.posted') })\n galleryChanged()\n this.dispatchEvent(new CustomEvent('gallery-posted', { detail: post, bubbles: true, composed: true }))\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.progress = undefined\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -9,11 +9,14 @@ export declare class GalleryViewer extends GalleryViewer_base {
9
9
  static styles: import("lit").CSSResult[];
10
10
  post: Post;
11
11
  private index;
12
- private likers?;
12
+ /** Who liked it is shown under the heart once asked. */
13
+ private showingLikers;
13
14
  private hiding;
14
15
  private reason;
15
16
  private burst;
16
17
  private busy;
18
+ private likersRead;
19
+ private get likers();
17
20
  render(): typeof nothing | import("lit-html").TemplateResult<1>;
18
21
  private replace;
19
22
  /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */
@@ -9,8 +9,10 @@ import '@material/web/button/filled-button.js';
9
9
  import '@material/web/button/text-button.js';
10
10
  import '@material/web/icon/icon.js';
11
11
  import '@operato/popup/ox-popup-actions.js';
12
+ import gql from 'graphql-tag';
12
13
  import { css, html, LitElement, nothing } from 'lit';
13
14
  import { customElement, property, state } from 'lit/decorators.js';
15
+ import { QueryController } from '@operato/graphql';
14
16
  import { i18next, localize } from '@operato/i18n';
15
17
  import { notify } from '@operato/layout';
16
18
  import { OxPrompt } from '@operato/popup/ox-prompt.js';
@@ -21,10 +23,15 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
21
23
  constructor() {
22
24
  super(...arguments);
23
25
  this.index = 0;
26
+ /** Who liked it is shown under the heart once asked. */
27
+ this.showingLikers = false;
24
28
  this.hiding = false;
25
29
  this.reason = '';
26
30
  this.burst = 0;
27
31
  this.busy = false;
32
+ this.likersRead = new QueryController(this, gql `query ($id: String!) { galleryLikers(id: $id) { id name } }`, {
33
+ variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)
34
+ });
28
35
  }
29
36
  static { this.styles = [
30
37
  CommonPopupStyles,
@@ -195,6 +202,9 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
195
202
  }
196
203
  `
197
204
  ]; }
205
+ get likers() {
206
+ return this.likersRead.data?.galleryLikers;
207
+ }
198
208
  render() {
199
209
  const post = this.post;
200
210
  if (!post)
@@ -308,8 +318,8 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
308
318
  try {
309
319
  const state = await galleryApi.like(post.id, like);
310
320
  this.post = { ...post, likeCount: state.likeCount, liked: state.liked };
311
- if (this.likers)
312
- this.likers = await galleryApi.likers(post.id);
321
+ if (this.showingLikers)
322
+ this.likersRead.refetch();
313
323
  this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }));
314
324
  }
315
325
  catch (error) {
@@ -319,17 +329,8 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
319
329
  this.busy = false;
320
330
  }
321
331
  }
322
- async showLikers() {
323
- if (this.likers) {
324
- this.likers = undefined;
325
- return;
326
- }
327
- try {
328
- this.likers = await galleryApi.likers(this.post.id);
329
- }
330
- catch (error) {
331
- notify({ level: 'error', message: reasonOf(error) });
332
- }
332
+ showLikers() {
333
+ this.showingLikers = !this.showingLikers;
333
334
  }
334
335
  edit() {
335
336
  this.close({ edit: this.post });
@@ -404,8 +405,8 @@ __decorate([
404
405
  ], GalleryViewer.prototype, "index", void 0);
405
406
  __decorate([
406
407
  state(),
407
- __metadata("design:type", Array)
408
- ], GalleryViewer.prototype, "likers", void 0);
408
+ __metadata("design:type", Object)
409
+ ], GalleryViewer.prototype, "showingLikers", void 0);
409
410
  __decorate([
410
411
  state(),
411
412
  __metadata("design:type", Object)
@@ -1 +1 @@
1
- {"version":3,"file":"gallery-viewer.js","sourceRoot":"","sources":["../../client/components/gallery-viewer.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,OAAO,uCAAuC,CAAA;AAC9C,OAAO,qCAAqC,CAAA;AAC5C,OAAO,4BAA4B,CAAA;AACnC,OAAO,oCAAoC,CAAA;AAE3C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEpE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAa,MAAM,yBAAyB,CAAA;AAC/E,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAG3D,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAzD;;QA6KY,UAAK,GAAG,CAAC,CAAA;QAET,WAAM,GAAG,KAAK,CAAA;QACd,WAAM,GAAG,EAAE,CAAA;QACX,UAAK,GAAG,CAAC,CAAA;QACT,SAAI,GAAG,KAAK,CAAA;IAgN/B,CAAC;aAjYQ,WAAM,GAAG;QACd,iBAAiB;QACjB,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoKF;KACF,AAxKY,CAwKZ;IAWD,MAAM;QACJ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAA;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;QACnC,OAAO,IAAI,CAAA;UACL,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAA,uBAAuB,CAAC,CAAC,0BAA0B,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO;uCAClH,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;YACtD,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,KAAK,CAAC,QAAQ,QAAQ,IAAI,CAAC,OAAO,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO;YAC/E,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,oCAAoC,CAAC,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,sBAAsB,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,yCAAyC,CAAC,CAAC,CAAC,OAAO;YAC5O,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,oFAAoF,CAAC,CAAC,CAAC,OAAO;YAE/G,IAAI;YACF,CAAC,CAAC,IAAI,CAAA,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA,4CAA4C,CAAC,CAAC,yBAAyB,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,OAAO;oBACvL,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA,wCAAwC,CAAC,CAAC,qBAAqB,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,4CAA4C,CAAC,CAAC,CAAC,OAAO;wCAC9K,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,SAAS;YACzE,CAAC,CAAC,OACN;;;;;;2BAMiB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;yBACpB,CAAC,CAAC,qBAAqB,CAAC;wBACzB,IAAI,CAAC,IAAI;qBACZ,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;;;;2CAIN,CAAC,IAAI,CAAC,SAAS,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;cAC9E,CAAC,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;;;wCAG7B,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC;cAClF,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE;;kBAEpB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;;UAEzB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA,uBAAuB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;UACtG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,sBAAsB,IAAI,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO;;;YAInE,IAAI,CAAC,KAAK;YACR,CAAC,CAAC,IAAI,CAAA,+BAA+B,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,sBAAsB,IAAI,CAAC,KAAM,CAAC,EAAE,EAAE,CAAC;4CAC5D,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;0BACjF;YACZ,CAAC,CAAC,OACN;YACE,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,+BAA+B,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,oBAAoB,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC;YAChJ,IAAI,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA,SAAS,CAAC,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO;;;UAIhJ,IAAI,CAAC,MAAM;YACT,CAAC,CAAC,IAAI,CAAA;;;gCAGc,CAAC,CAAC,0BAA0B,CAAC;2BAClC,IAAI,CAAC,MAAM;2BACX,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;qBAEhD;YACT,CAAC,CAAC,OACN;;;UAIE,IAAI,CAAC,QAAQ;YACX,CAAC,CAAC,IAAI,CAAA,6BAA6B,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;qBAC/D,CAAC,CAAC,qBAAqB,CAAC;;4CAED,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;qBAClE,CAAC,CAAC,uBAAuB,CAAC;kBAC7B;YACN,CAAC,CAAC,OACN;UAEE,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,MAAM;YAC9B,CAAC,CAAC,IAAI,CAAC,QAAQ;gBACb,CAAC,CAAC,IAAI,CAAA,6BAA6B,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;qBACnE,CAAC,CAAC,uBAAuB,CAAC;kBAC7B;gBACJ,CAAC,CAAC,IAAI,CAAA,6BAA6B,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;qBAC1E,CAAC,CAAC,qBAAqB,CAAC;kBAC3B;YACN,CAAC,CAAC,OACN;UAEE,IAAI,CAAC,MAAM;YACT,CAAC,CAAC,IAAI,CAAA,wCAAwC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;qBAChE,CAAC,CAAC,uBAAuB,CAAC;;;;8BAIjB,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;2BACnC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;qBACvB,CAAC,CAAC,qBAAqB,CAAC;kBAC3B;YACN,CAAC,CAAC,IAAI,CAAA,2CAA2C,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE;mBAC5D,CAAC,CAAC,sBAAsB,CAAC;gBAEpC;0BACkB,CAAA;IACxB,CAAC;IAEO,OAAO,CAAC,IAAU;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;QACtE,cAAc,EAAE,CAAA;IAClB,CAAC;IAED,0GAA0G;IAClG,KAAK,CAAC,IAAI,CAAC,IAAa,EAAE,SAAS,GAAG,KAAK;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,KAAK,EAAE,CAAA;YACZ,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;YACvC,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAM;QACxB,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;YAClD,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAA;YACvE,IAAI,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC/D,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC5G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;YACvB,OAAM;QACR,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACjC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;YAC/B,KAAK,EAAE,CAAC,CAAC,uBAAuB,CAAC;YACjC,IAAI,EAAE,CAAC,CAAC,6BAA6B,CAAC;YACtC,aAAa,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,uBAAuB,CAAC,EAAE;YACnD,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,uBAAuB,CAAC,EAAE;SACnD,CAAC,CAAA;QACF,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACrC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAA;YAC9C,cAAc,EAAE,CAAA;YAChB,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAA;YAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YACrE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;YACnB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;YAChB,gEAAgE;YAChE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAA;QACzF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,EAAE,CAAC,OAAe;QACxB,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,6JAA6J;IACrJ,KAAK,CAAC,IAA6E;QACzF,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC9F,CAAC;;AAtN+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;2CAAY;AAE1B;IAAhB,KAAK,EAAE;;4CAAkB;AACT;IAAhB,KAAK,EAAE;;6CAAiD;AACxC;IAAhB,KAAK,EAAE;;6CAAuB;AACd;IAAhB,KAAK,EAAE;;6CAAoB;AACX;IAAhB,KAAK,EAAE;;4CAAkB;AACT;IAAhB,KAAK,EAAE;;2CAAqB;AAlLlB,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAkYzB","sourcesContent":["/*\n * One post seen large (ADR-0165 decisions 4-6): its photos one by one - and across the whole screen (decision 9) - the like (the heart, or a double press on the\n * photo), who posted it and when, its event and tags - each opens the gallery narrowed to it. Its owner changes or\n * deletes it here; a moderator hides it here, with the reason, or shows it again. Where to go next is the popup's result\n * - a popup closes by going back in the history, so a page opened before it is gone would be gone with it.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { galleryApi, galleryChanged, type Post } from '../utils/gallery-api.js'\nimport { day, days, reasonOf, t } from '../utils/gallery-words.js'\n\n@customElement('gallery-viewer')\nexport class GalleryViewer extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .stage {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n max-height: 62vh;\n background: var(--md-sys-color-surface-container-highest);\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n user-select: none;\n }\n .stage img {\n max-width: 100%;\n max-height: 62vh;\n object-fit: contain;\n display: block;\n }\n .stage .turn {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .previous {\n inset-inline-start: var(--spacing-small, 4px);\n }\n .stage .next {\n inset-inline-end: var(--spacing-small, 4px);\n }\n .stage .large {\n position: absolute;\n top: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-small, 4px);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .index {\n position: absolute;\n bottom: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-medium, 8px);\n padding: 0 6px;\n border-radius: 999px;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n font-size: var(--ui-t-small, 12px);\n }\n .burst {\n position: absolute;\n --md-icon-size: 72px;\n color: #fff;\n opacity: 0.9;\n animation: burst 600ms ease-out forwards;\n pointer-events: none;\n }\n @keyframes burst {\n from {\n transform: scale(0.6);\n opacity: 0.9;\n }\n to {\n transform: scale(1.3);\n opacity: 0;\n }\n }\n .line {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .heart {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n cursor: pointer;\n }\n /* The app's icons are drawn filled; an empty heart says not liked yet. */\n .heart md-icon {\n --md-icon-size: 22px;\n font-variation-settings: 'FILL' 0;\n }\n .heart[aria-pressed='true'] md-icon {\n color: var(--md-sys-color-error);\n font-variation-settings: 'FILL' 1;\n }\n .link {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n cursor: pointer;\n }\n .link:hover {\n text-decoration: underline;\n }\n .link md-icon {\n --md-icon-size: 14px;\n }\n .caption {\n margin: 0;\n font-size: var(--ui-t-body, 14px);\n line-height: 1.6;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n color: var(--md-sys-color-on-surface);\n }\n .hidden {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-error-container);\n color: var(--md-sys-color-on-error-container);\n font-size: var(--ui-t-small, 12px);\n }\n .likers {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 56px;\n font: inherit;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n .spacer {\n margin-inline-end: auto;\n }\n `\n ]\n\n @property({ attribute: false }) post!: Post\n\n @state() private index = 0\n @state() private likers?: { id: string; name?: string }[]\n @state() private hiding = false\n @state() private reason = ''\n @state() private burst = 0\n @state() private busy = false\n\n render() {\n const post = this.post\n if (!post) return nothing\n const photo = post.photos[this.index]\n const many = post.photos.length > 1\n return html`<div class=\"body\">\n ${post.hiddenAt ? html`<div class=\"hidden\">${t('gallery.text.hidden-note')}${post.hiddenReason ? ` · ${post.hiddenReason}` : ''}</div>` : nothing}\n <div class=\"stage\" @dblclick=${() => this.like(true, true)}>\n ${photo ? html`<img src=${photo.fullpath} alt=${post.caption ?? ''} />` : nothing}\n ${photo ? html`<button class=\"large\" aria-label=${t('gallery.button.large')} title=${t('gallery.button.large')} @click=${() => this.close({ show: { postId: post.id, index: this.index } })}><md-icon>fullscreen</md-icon></button>` : nothing}\n ${this.burst ? html`<md-icon class=\"burst\" style=\"font-variation-settings:'FILL' 1\">favorite</md-icon>` : nothing}\n ${\n many\n ? html`${this.index > 0 ? html`<button class=\"turn previous\" aria-label=${t('gallery.button.previous')} @click=${() => (this.index -= 1)}><md-icon>chevron_left</md-icon></button>` : nothing}\n ${this.index < post.photos.length - 1 ? html`<button class=\"turn next\" aria-label=${t('gallery.button.next')} @click=${() => (this.index += 1)}><md-icon>chevron_right</md-icon></button>` : nothing}\n <span class=\"index\">${this.index + 1} / ${post.photos.length}</span>`\n : nothing\n }\n </div>\n\n <div class=\"line\">\n <button\n class=\"heart\"\n aria-pressed=${String(post.liked)}\n aria-label=${t('gallery.button.like')}\n ?disabled=${this.busy}\n @click=${() => this.like(!post.liked)}\n >\n <md-icon>favorite</md-icon>\n </button>\n <button class=\"link\" ?disabled=${!post.likeCount} @click=${() => this.showLikers()}>\n ${t('gallery.text.like-count', { count: post.likeCount })}\n </button>\n <span class=\"spacer\"></span>\n <button class=\"link\" @click=${() => this.go(`gallery-page?author=${post.creator?.id}`)}>\n ${post.creator?.name ?? ''}\n </button>\n <span>${day(post.takenAt)}</span>\n </div>\n ${this.likers ? html`<div class=\"likers\">${this.likers.map(one => one.name).join(', ')}</div>` : nothing}\n ${post.caption ? html`<p class=\"caption\">${post.caption}</p>` : nothing}\n\n <div class=\"line\">\n ${\n post.event\n ? html`<button class=\"link\" @click=${() => this.go(`gallery-page?event=${post.event!.id}`)}>\n <md-icon>event</md-icon>${post.event.name} · ${days(post.event.startAt, post.event.endAt)}\n </button>`\n : nothing\n }\n ${(post.tags ?? []).map(tag => html`<button class=\"link\" @click=${() => this.go(`gallery-page?tag=${encodeURIComponent(tag)}`)}>#${tag}</button>`)}\n ${post.space === 'PERSONAL' ? html`<span>${t('gallery.space.PERSONAL')}${post.shared ? '' : ` · ${t('gallery.text.only-me')}`}</span>` : nothing}\n </div>\n\n ${\n this.hiding\n ? html`<div>\n <textarea\n maxlength=\"200\"\n placeholder=${t('gallery.text.hide-reason')}\n .value=${this.reason}\n @input=${(e: any) => (this.reason = e.target.value)}\n ></textarea>\n </div>`\n : nothing\n }\n </div>\n <ox-popup-actions>\n ${\n post.editable\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.edit()}\n >${t('gallery.button.edit')}</md-text-button\n >\n <md-text-button ?disabled=${this.busy} @click=${() => this.deletePost()}\n >${t('gallery.button.delete')}</md-text-button\n >`\n : nothing\n }\n ${\n post.moderatable && !this.hiding\n ? post.hiddenAt\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.unhide()}\n >${t('gallery.button.unhide')}</md-text-button\n >`\n : html`<md-text-button ?disabled=${this.busy} @click=${() => (this.hiding = true)}\n >${t('gallery.button.hide')}</md-text-button\n >`\n : nothing\n }\n ${\n this.hiding\n ? html`<md-text-button slot=\"cancel\" @click=${() => (this.hiding = false)}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button\n slot=\"confirm\"\n ?disabled=${this.busy || !this.reason.trim()}\n @click=${() => this.hide()}\n >${t('gallery.button.hide')}</md-filled-button\n >`\n : html`<md-filled-button slot=\"confirm\" @click=${() => this.close()}\n >${t('gallery.button.close')}</md-filled-button\n >`\n }\n </ox-popup-actions>`\n }\n\n private replace(post: Post) {\n this.post = post\n this.index = Math.min(this.index, Math.max(0, post.photos.length - 1))\n galleryChanged()\n }\n\n /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */\n private async like(like: boolean, fromPhoto = false) {\n const post = this.post\n if (fromPhoto) {\n this.burst++\n setTimeout(() => (this.burst = 0), 600)\n if (post.liked) return\n }\n this.busy = true\n try {\n const state = await galleryApi.like(post.id, like)\n this.post = { ...post, likeCount: state.likeCount, liked: state.liked }\n if (this.likers) this.likers = await galleryApi.likers(post.id)\n this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async showLikers() {\n if (this.likers) {\n this.likers = undefined\n return\n }\n try {\n this.likers = await galleryApi.likers(this.post.id)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n }\n }\n\n private edit() {\n this.close({ edit: this.post })\n }\n\n private async deletePost() {\n const sure = await OxPrompt.open({\n title: t('gallery.button.delete'),\n text: t('gallery.text.delete-confirm'),\n confirmButton: { text: t('gallery.button.delete') },\n cancelButton: { text: t('gallery.button.cancel') }\n })\n if (!sure) return\n this.busy = true\n try {\n await galleryApi.remove(this.post.id)\n notify({ message: t('gallery.text.deleted') })\n galleryChanged()\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async hide() {\n this.busy = true\n try {\n const own = this.post.editable\n this.replace(await galleryApi.hide(this.post.id, this.reason.trim()))\n this.hiding = false\n this.reason = ''\n /* Its owner is told - unless the one hiding it is its owner. */\n notify({ message: own ? t('gallery.text.hidden-own') : t('gallery.text.hidden-done') })\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async unhide() {\n this.busy = true\n try {\n this.replace(await galleryApi.unhide(this.post.id))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private go(address: string) {\n this.close({ go: address })\n }\n\n /** The next step - a page to go to, the post to change, or the photo to see large - goes as the popup's result: the page takes it once the popup is gone. */\n private close(next?: { go?: string; edit?: Post; show?: { postId: string; index: number } }) {\n this.dispatchEvent(new CustomEvent('done', { detail: next, bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"gallery-viewer.js","sourceRoot":"","sources":["../../client/components/gallery-viewer.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * One post seen large (ADR-0165 decisions 4-6): its photos one by one - and across the whole screen (decision 9) - the like (the heart, or a double press on the\n * photo), who posted it and when, its event and tags - each opens the gallery narrowed to it. Its owner changes or\n * deletes it here; a moderator hides it here, with the reason, or shows it again. Where to go next is the popup's result\n * - a popup closes by going back in the history, so a page opened before it is gone would be gone with it.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { galleryApi, galleryChanged, type Post } from '../utils/gallery-api.js'\nimport { day, days, reasonOf, t } from '../utils/gallery-words.js'\n\n@customElement('gallery-viewer')\nexport class GalleryViewer extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .stage {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n max-height: 62vh;\n background: var(--md-sys-color-surface-container-highest);\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n user-select: none;\n }\n .stage img {\n max-width: 100%;\n max-height: 62vh;\n object-fit: contain;\n display: block;\n }\n .stage .turn {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .previous {\n inset-inline-start: var(--spacing-small, 4px);\n }\n .stage .next {\n inset-inline-end: var(--spacing-small, 4px);\n }\n .stage .large {\n position: absolute;\n top: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-small, 4px);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .index {\n position: absolute;\n bottom: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-medium, 8px);\n padding: 0 6px;\n border-radius: 999px;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n font-size: var(--ui-t-small, 12px);\n }\n .burst {\n position: absolute;\n --md-icon-size: 72px;\n color: #fff;\n opacity: 0.9;\n animation: burst 600ms ease-out forwards;\n pointer-events: none;\n }\n @keyframes burst {\n from {\n transform: scale(0.6);\n opacity: 0.9;\n }\n to {\n transform: scale(1.3);\n opacity: 0;\n }\n }\n .line {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .heart {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n cursor: pointer;\n }\n /* The app's icons are drawn filled; an empty heart says not liked yet. */\n .heart md-icon {\n --md-icon-size: 22px;\n font-variation-settings: 'FILL' 0;\n }\n .heart[aria-pressed='true'] md-icon {\n color: var(--md-sys-color-error);\n font-variation-settings: 'FILL' 1;\n }\n .link {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n cursor: pointer;\n }\n .link:hover {\n text-decoration: underline;\n }\n .link md-icon {\n --md-icon-size: 14px;\n }\n .caption {\n margin: 0;\n font-size: var(--ui-t-body, 14px);\n line-height: 1.6;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n color: var(--md-sys-color-on-surface);\n }\n .hidden {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-error-container);\n color: var(--md-sys-color-on-error-container);\n font-size: var(--ui-t-small, 12px);\n }\n .likers {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 56px;\n font: inherit;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n .spacer {\n margin-inline-end: auto;\n }\n `\n ]\n\n @property({ attribute: false }) post!: Post\n\n @state() private index = 0\n /** Who liked it is shown under the heart once asked. */\n @state() private showingLikers = false\n @state() private hiding = false\n @state() private reason = ''\n @state() private burst = 0\n @state() private busy = false\n\n private likersRead = new QueryController(this, gql`query ($id: String!) { galleryLikers(id: $id) { id name } }`, {\n variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)\n })\n\n private get likers(): { id: string; name?: string }[] | undefined {\n return this.likersRead.data?.galleryLikers\n }\n\n render() {\n const post = this.post\n if (!post) return nothing\n const photo = post.photos[this.index]\n const many = post.photos.length > 1\n return html`<div class=\"body\">\n ${post.hiddenAt ? html`<div class=\"hidden\">${t('gallery.text.hidden-note')}${post.hiddenReason ? ` · ${post.hiddenReason}` : ''}</div>` : nothing}\n <div class=\"stage\" @dblclick=${() => this.like(true, true)}>\n ${photo ? html`<img src=${photo.fullpath} alt=${post.caption ?? ''} />` : nothing}\n ${photo ? html`<button class=\"large\" aria-label=${t('gallery.button.large')} title=${t('gallery.button.large')} @click=${() => this.close({ show: { postId: post.id, index: this.index } })}><md-icon>fullscreen</md-icon></button>` : nothing}\n ${this.burst ? html`<md-icon class=\"burst\" style=\"font-variation-settings:'FILL' 1\">favorite</md-icon>` : nothing}\n ${\n many\n ? html`${this.index > 0 ? html`<button class=\"turn previous\" aria-label=${t('gallery.button.previous')} @click=${() => (this.index -= 1)}><md-icon>chevron_left</md-icon></button>` : nothing}\n ${this.index < post.photos.length - 1 ? html`<button class=\"turn next\" aria-label=${t('gallery.button.next')} @click=${() => (this.index += 1)}><md-icon>chevron_right</md-icon></button>` : nothing}\n <span class=\"index\">${this.index + 1} / ${post.photos.length}</span>`\n : nothing\n }\n </div>\n\n <div class=\"line\">\n <button\n class=\"heart\"\n aria-pressed=${String(post.liked)}\n aria-label=${t('gallery.button.like')}\n ?disabled=${this.busy}\n @click=${() => this.like(!post.liked)}\n >\n <md-icon>favorite</md-icon>\n </button>\n <button class=\"link\" ?disabled=${!post.likeCount} @click=${() => this.showLikers()}>\n ${t('gallery.text.like-count', { count: post.likeCount })}\n </button>\n <span class=\"spacer\"></span>\n <button class=\"link\" @click=${() => this.go(`gallery-page?author=${post.creator?.id}`)}>\n ${post.creator?.name ?? ''}\n </button>\n <span>${day(post.takenAt)}</span>\n </div>\n ${this.likers ? html`<div class=\"likers\">${this.likers.map(one => one.name).join(', ')}</div>` : nothing}\n ${post.caption ? html`<p class=\"caption\">${post.caption}</p>` : nothing}\n\n <div class=\"line\">\n ${\n post.event\n ? html`<button class=\"link\" @click=${() => this.go(`gallery-page?event=${post.event!.id}`)}>\n <md-icon>event</md-icon>${post.event.name} · ${days(post.event.startAt, post.event.endAt)}\n </button>`\n : nothing\n }\n ${(post.tags ?? []).map(tag => html`<button class=\"link\" @click=${() => this.go(`gallery-page?tag=${encodeURIComponent(tag)}`)}>#${tag}</button>`)}\n ${post.space === 'PERSONAL' ? html`<span>${t('gallery.space.PERSONAL')}${post.shared ? '' : ` · ${t('gallery.text.only-me')}`}</span>` : nothing}\n </div>\n\n ${\n this.hiding\n ? html`<div>\n <textarea\n maxlength=\"200\"\n placeholder=${t('gallery.text.hide-reason')}\n .value=${this.reason}\n @input=${(e: any) => (this.reason = e.target.value)}\n ></textarea>\n </div>`\n : nothing\n }\n </div>\n <ox-popup-actions>\n ${\n post.editable\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.edit()}\n >${t('gallery.button.edit')}</md-text-button\n >\n <md-text-button ?disabled=${this.busy} @click=${() => this.deletePost()}\n >${t('gallery.button.delete')}</md-text-button\n >`\n : nothing\n }\n ${\n post.moderatable && !this.hiding\n ? post.hiddenAt\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.unhide()}\n >${t('gallery.button.unhide')}</md-text-button\n >`\n : html`<md-text-button ?disabled=${this.busy} @click=${() => (this.hiding = true)}\n >${t('gallery.button.hide')}</md-text-button\n >`\n : nothing\n }\n ${\n this.hiding\n ? html`<md-text-button slot=\"cancel\" @click=${() => (this.hiding = false)}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button\n slot=\"confirm\"\n ?disabled=${this.busy || !this.reason.trim()}\n @click=${() => this.hide()}\n >${t('gallery.button.hide')}</md-filled-button\n >`\n : html`<md-filled-button slot=\"confirm\" @click=${() => this.close()}\n >${t('gallery.button.close')}</md-filled-button\n >`\n }\n </ox-popup-actions>`\n }\n\n private replace(post: Post) {\n this.post = post\n this.index = Math.min(this.index, Math.max(0, post.photos.length - 1))\n galleryChanged()\n }\n\n /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */\n private async like(like: boolean, fromPhoto = false) {\n const post = this.post\n if (fromPhoto) {\n this.burst++\n setTimeout(() => (this.burst = 0), 600)\n if (post.liked) return\n }\n this.busy = true\n try {\n const state = await galleryApi.like(post.id, like)\n this.post = { ...post, likeCount: state.likeCount, liked: state.liked }\n if (this.showingLikers) this.likersRead.refetch()\n this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private showLikers() {\n this.showingLikers = !this.showingLikers\n }\n\n private edit() {\n this.close({ edit: this.post })\n }\n\n private async deletePost() {\n const sure = await OxPrompt.open({\n title: t('gallery.button.delete'),\n text: t('gallery.text.delete-confirm'),\n confirmButton: { text: t('gallery.button.delete') },\n cancelButton: { text: t('gallery.button.cancel') }\n })\n if (!sure) return\n this.busy = true\n try {\n await galleryApi.remove(this.post.id)\n notify({ message: t('gallery.text.deleted') })\n galleryChanged()\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async hide() {\n this.busy = true\n try {\n const own = this.post.editable\n this.replace(await galleryApi.hide(this.post.id, this.reason.trim()))\n this.hiding = false\n this.reason = ''\n /* Its owner is told - unless the one hiding it is its owner. */\n notify({ message: own ? t('gallery.text.hidden-own') : t('gallery.text.hidden-done') })\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async unhide() {\n this.busy = true\n try {\n this.replace(await galleryApi.unhide(this.post.id))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private go(address: string) {\n this.close({ go: address })\n }\n\n /** The next step - a page to go to, the post to change, or the photo to see large - goes as the popup's result: the page takes it once the popup is gone. */\n private close(next?: { go?: string; edit?: Post; show?: { postId: string; index: number } }) {\n this.dispatchEvent(new CustomEvent('done', { detail: next, bubbles: true, composed: true }))\n }\n}\n"]}