@things-factory/gallery 10.1.248 → 10.1.249

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist-client/bootstrap.d.ts +2 -0
  2. package/dist-client/bootstrap.js +26 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/components/gallery-forms.d.ts +31 -0
  5. package/dist-client/components/gallery-forms.js +223 -0
  6. package/dist-client/components/gallery-forms.js.map +1 -0
  7. package/dist-client/components/gallery-saver-setting-let.d.ts +11 -0
  8. package/dist-client/components/gallery-saver-setting-let.js +81 -0
  9. package/dist-client/components/gallery-saver-setting-let.js.map +1 -0
  10. package/dist-client/components/gallery-show.d.ts +46 -0
  11. package/dist-client/components/gallery-show.js +316 -0
  12. package/dist-client/components/gallery-show.js.map +1 -0
  13. package/dist-client/components/gallery-uploader.d.ts +57 -0
  14. package/dist-client/components/gallery-uploader.js +624 -0
  15. package/dist-client/components/gallery-uploader.js.map +1 -0
  16. package/dist-client/components/gallery-viewer.d.ts +30 -0
  17. package/dist-client/components/gallery-viewer.js +429 -0
  18. package/dist-client/components/gallery-viewer.js.map +1 -0
  19. package/dist-client/index.d.ts +1 -0
  20. package/dist-client/index.js +2 -0
  21. package/dist-client/index.js.map +1 -0
  22. package/dist-client/pages/gallery-page.d.ts +54 -0
  23. package/dist-client/pages/gallery-page.js +590 -0
  24. package/dist-client/pages/gallery-page.js.map +1 -0
  25. package/dist-client/route.d.ts +1 -0
  26. package/dist-client/route.js +9 -0
  27. package/dist-client/route.js.map +1 -0
  28. package/dist-client/tsconfig.tsbuildinfo +1 -0
  29. package/dist-client/utils/gallery-api.d.ts +99 -0
  30. package/dist-client/utils/gallery-api.js +46 -0
  31. package/dist-client/utils/gallery-api.js.map +1 -0
  32. package/dist-client/utils/gallery-badge.d.ts +4 -0
  33. package/dist-client/utils/gallery-badge.js +45 -0
  34. package/dist-client/utils/gallery-badge.js.map +1 -0
  35. package/dist-client/utils/gallery-saver.d.ts +6 -0
  36. package/dist-client/utils/gallery-saver.js +69 -0
  37. package/dist-client/utils/gallery-saver.js.map +1 -0
  38. package/dist-client/utils/gallery-words.d.ts +7 -0
  39. package/dist-client/utils/gallery-words.js +20 -0
  40. package/dist-client/utils/gallery-words.js.map +1 -0
  41. package/dist-client/utils/photo-prep.d.ts +10 -0
  42. package/dist-client/utils/photo-prep.js +102 -0
  43. package/dist-client/utils/photo-prep.js.map +1 -0
  44. package/dist-server/attachment-reader.d.ts +1 -0
  45. package/dist-server/attachment-reader.js +13 -0
  46. package/dist-server/attachment-reader.js.map +1 -0
  47. package/dist-server/index.d.ts +1 -0
  48. package/dist-server/index.js +11 -0
  49. package/dist-server/index.js.map +1 -0
  50. package/dist-server/role-tasks.d.ts +2 -0
  51. package/dist-server/role-tasks.js +15 -0
  52. package/dist-server/role-tasks.js.map +1 -0
  53. package/dist-server/service/gallery/gallery-resolver.d.ts +29 -0
  54. package/dist-server/service/gallery/gallery-resolver.js +613 -0
  55. package/dist-server/service/gallery/gallery-resolver.js.map +1 -0
  56. package/dist-server/service/gallery/gallery-rules.d.ts +90 -0
  57. package/dist-server/service/gallery/gallery-rules.js +182 -0
  58. package/dist-server/service/gallery/gallery-rules.js.map +1 -0
  59. package/dist-server/service/gallery/gallery-service.d.ts +37 -0
  60. package/dist-server/service/gallery/gallery-service.js +234 -0
  61. package/dist-server/service/gallery/gallery-service.js.map +1 -0
  62. package/dist-server/service/gallery/gallery-types.d.ts +65 -0
  63. package/dist-server/service/gallery/gallery-types.js +239 -0
  64. package/dist-server/service/gallery/gallery-types.js.map +1 -0
  65. package/dist-server/service/gallery/gallery.d.ts +84 -0
  66. package/dist-server/service/gallery/gallery.js +335 -0
  67. package/dist-server/service/gallery/gallery.js.map +1 -0
  68. package/dist-server/service/gallery/index.d.ts +4 -0
  69. package/dist-server/service/gallery/index.js +8 -0
  70. package/dist-server/service/gallery/index.js.map +1 -0
  71. package/dist-server/service/index.d.ts +7 -0
  72. package/dist-server/service/index.js +23 -0
  73. package/dist-server/service/index.js.map +1 -0
  74. package/dist-server/tsconfig.tsbuildinfo +1 -0
  75. package/package.json +2 -2
@@ -0,0 +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"]}
@@ -0,0 +1,30 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
3
+ import '@material/web/icon/icon.js';
4
+ import '@operato/popup/ox-popup-actions.js';
5
+ import { LitElement, nothing } from 'lit';
6
+ import { type Post } from '../utils/gallery-api.js';
7
+ declare const GalleryViewer_base: (new (...args: any[]) => LitElement) & typeof LitElement;
8
+ export declare class GalleryViewer extends GalleryViewer_base {
9
+ static styles: import("lit").CSSResult[];
10
+ post: Post;
11
+ private index;
12
+ private likers?;
13
+ private hiding;
14
+ private reason;
15
+ private burst;
16
+ private busy;
17
+ render(): typeof nothing | import("lit-html").TemplateResult<1>;
18
+ private replace;
19
+ /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */
20
+ private like;
21
+ private showLikers;
22
+ private edit;
23
+ private deletePost;
24
+ private hide;
25
+ private unhide;
26
+ private go;
27
+ /** 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. */
28
+ private close;
29
+ }
30
+ export {};
@@ -0,0 +1,429 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ /*
3
+ * 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
4
+ * photo), who posted it and when, its event and tags - each opens the gallery narrowed to it. Its owner changes or
5
+ * deletes it here; a moderator hides it here, with the reason, or shows it again. Where to go next is the popup's result
6
+ * - a popup closes by going back in the history, so a page opened before it is gone would be gone with it.
7
+ */
8
+ import '@material/web/button/filled-button.js';
9
+ import '@material/web/button/text-button.js';
10
+ import '@material/web/icon/icon.js';
11
+ import '@operato/popup/ox-popup-actions.js';
12
+ import { css, html, LitElement, nothing } from 'lit';
13
+ import { customElement, property, state } from 'lit/decorators.js';
14
+ import { i18next, localize } from '@operato/i18n';
15
+ import { notify } from '@operato/layout';
16
+ import { OxPrompt } from '@operato/popup/ox-prompt.js';
17
+ import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles';
18
+ import { galleryApi, galleryChanged } from '../utils/gallery-api.js';
19
+ import { day, days, reasonOf, t } from '../utils/gallery-words.js';
20
+ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.index = 0;
24
+ this.hiding = false;
25
+ this.reason = '';
26
+ this.burst = 0;
27
+ this.busy = false;
28
+ }
29
+ static { this.styles = [
30
+ CommonPopupStyles,
31
+ PopupBodyStyles,
32
+ css `
33
+ :host {
34
+ height: 100%;
35
+ }
36
+ .body {
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: var(--spacing-medium, 8px);
40
+ }
41
+ .stage {
42
+ position: relative;
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ min-height: 240px;
47
+ max-height: 62vh;
48
+ background: var(--md-sys-color-surface-container-highest);
49
+ border-radius: var(--border-radius, 4px);
50
+ overflow: hidden;
51
+ user-select: none;
52
+ }
53
+ .stage img {
54
+ max-width: 100%;
55
+ max-height: 62vh;
56
+ object-fit: contain;
57
+ display: block;
58
+ }
59
+ .stage .turn {
60
+ position: absolute;
61
+ top: 50%;
62
+ transform: translateY(-50%);
63
+ display: inline-flex;
64
+ padding: 4px;
65
+ border: 0;
66
+ border-radius: 50%;
67
+ background: rgb(0 0 0 / 45%);
68
+ color: #fff;
69
+ cursor: pointer;
70
+ }
71
+ .stage .previous {
72
+ inset-inline-start: var(--spacing-small, 4px);
73
+ }
74
+ .stage .next {
75
+ inset-inline-end: var(--spacing-small, 4px);
76
+ }
77
+ .stage .large {
78
+ position: absolute;
79
+ top: var(--spacing-small, 4px);
80
+ inset-inline-end: var(--spacing-small, 4px);
81
+ display: inline-flex;
82
+ padding: 4px;
83
+ border: 0;
84
+ border-radius: 50%;
85
+ background: rgb(0 0 0 / 45%);
86
+ color: #fff;
87
+ cursor: pointer;
88
+ }
89
+ .stage .index {
90
+ position: absolute;
91
+ bottom: var(--spacing-small, 4px);
92
+ inset-inline-end: var(--spacing-medium, 8px);
93
+ padding: 0 6px;
94
+ border-radius: 999px;
95
+ background: rgb(0 0 0 / 45%);
96
+ color: #fff;
97
+ font-size: var(--ui-t-small, 12px);
98
+ }
99
+ .burst {
100
+ position: absolute;
101
+ --md-icon-size: 72px;
102
+ color: #fff;
103
+ opacity: 0.9;
104
+ animation: burst 600ms ease-out forwards;
105
+ pointer-events: none;
106
+ }
107
+ @keyframes burst {
108
+ from {
109
+ transform: scale(0.6);
110
+ opacity: 0.9;
111
+ }
112
+ to {
113
+ transform: scale(1.3);
114
+ opacity: 0;
115
+ }
116
+ }
117
+ .line {
118
+ display: flex;
119
+ flex-wrap: wrap;
120
+ align-items: center;
121
+ gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);
122
+ font-size: var(--ui-t-small, 12px);
123
+ color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
124
+ }
125
+ .heart {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ gap: 2px;
129
+ padding: 0;
130
+ border: 0;
131
+ background: none;
132
+ color: var(--md-sys-color-on-surface);
133
+ font: inherit;
134
+ font-size: var(--ui-t-body, 14px);
135
+ cursor: pointer;
136
+ }
137
+ /* The app's icons are drawn filled; an empty heart says not liked yet. */
138
+ .heart md-icon {
139
+ --md-icon-size: 22px;
140
+ font-variation-settings: 'FILL' 0;
141
+ }
142
+ .heart[aria-pressed='true'] md-icon {
143
+ color: var(--md-sys-color-error);
144
+ font-variation-settings: 'FILL' 1;
145
+ }
146
+ .link {
147
+ display: inline-flex;
148
+ align-items: center;
149
+ gap: 2px;
150
+ padding: 0;
151
+ border: 0;
152
+ background: none;
153
+ color: var(--md-sys-color-primary);
154
+ font: inherit;
155
+ cursor: pointer;
156
+ }
157
+ .link:hover {
158
+ text-decoration: underline;
159
+ }
160
+ .link md-icon {
161
+ --md-icon-size: 14px;
162
+ }
163
+ .caption {
164
+ margin: 0;
165
+ font-size: var(--ui-t-body, 14px);
166
+ line-height: 1.6;
167
+ white-space: pre-wrap;
168
+ overflow-wrap: anywhere;
169
+ color: var(--md-sys-color-on-surface);
170
+ }
171
+ .hidden {
172
+ padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);
173
+ border-radius: var(--border-radius, 4px);
174
+ background: var(--md-sys-color-error-container);
175
+ color: var(--md-sys-color-on-error-container);
176
+ font-size: var(--ui-t-small, 12px);
177
+ }
178
+ .likers {
179
+ font-size: var(--ui-t-small, 12px);
180
+ color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
181
+ }
182
+ textarea {
183
+ box-sizing: border-box;
184
+ width: 100%;
185
+ min-height: 56px;
186
+ font: inherit;
187
+ padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);
188
+ border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));
189
+ border-radius: var(--border-radius, 4px);
190
+ background: var(--md-sys-color-surface);
191
+ color: var(--md-sys-color-on-surface);
192
+ }
193
+ .spacer {
194
+ margin-inline-end: auto;
195
+ }
196
+ `
197
+ ]; }
198
+ render() {
199
+ const post = this.post;
200
+ if (!post)
201
+ return nothing;
202
+ const photo = post.photos[this.index];
203
+ const many = post.photos.length > 1;
204
+ return html `<div class="body">
205
+ ${post.hiddenAt ? html `<div class="hidden">${t('gallery.text.hidden-note')}${post.hiddenReason ? ` · ${post.hiddenReason}` : ''}</div>` : nothing}
206
+ <div class="stage" @dblclick=${() => this.like(true, true)}>
207
+ ${photo ? html `<img src=${photo.fullpath} alt=${post.caption ?? ''} />` : nothing}
208
+ ${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}
209
+ ${this.burst ? html `<md-icon class="burst" style="font-variation-settings:'FILL' 1">favorite</md-icon>` : nothing}
210
+ ${many
211
+ ? 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}
212
+ ${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}
213
+ <span class="index">${this.index + 1} / ${post.photos.length}</span>`
214
+ : nothing}
215
+ </div>
216
+
217
+ <div class="line">
218
+ <button
219
+ class="heart"
220
+ aria-pressed=${String(post.liked)}
221
+ aria-label=${t('gallery.button.like')}
222
+ ?disabled=${this.busy}
223
+ @click=${() => this.like(!post.liked)}
224
+ >
225
+ <md-icon>favorite</md-icon>
226
+ </button>
227
+ <button class="link" ?disabled=${!post.likeCount} @click=${() => this.showLikers()}>
228
+ ${t('gallery.text.like-count', { count: post.likeCount })}
229
+ </button>
230
+ <span class="spacer"></span>
231
+ <button class="link" @click=${() => this.go(`gallery-page?author=${post.creator?.id}`)}>
232
+ ${post.creator?.name ?? ''}
233
+ </button>
234
+ <span>${day(post.takenAt)}</span>
235
+ </div>
236
+ ${this.likers ? html `<div class="likers">${this.likers.map(one => one.name).join(', ')}</div>` : nothing}
237
+ ${post.caption ? html `<p class="caption">${post.caption}</p>` : nothing}
238
+
239
+ <div class="line">
240
+ ${post.event
241
+ ? html `<button class="link" @click=${() => this.go(`gallery-page?event=${post.event.id}`)}>
242
+ <md-icon>event</md-icon>${post.event.name} · ${days(post.event.startAt, post.event.endAt)}
243
+ </button>`
244
+ : nothing}
245
+ ${(post.tags ?? []).map(tag => html `<button class="link" @click=${() => this.go(`gallery-page?tag=${encodeURIComponent(tag)}`)}>#${tag}</button>`)}
246
+ ${post.space === 'PERSONAL' ? html `<span>${t('gallery.space.PERSONAL')}${post.shared ? '' : ` · ${t('gallery.text.only-me')}`}</span>` : nothing}
247
+ </div>
248
+
249
+ ${this.hiding
250
+ ? html `<div>
251
+ <textarea
252
+ maxlength="200"
253
+ placeholder=${t('gallery.text.hide-reason')}
254
+ .value=${this.reason}
255
+ @input=${(e) => (this.reason = e.target.value)}
256
+ ></textarea>
257
+ </div>`
258
+ : nothing}
259
+ </div>
260
+ <ox-popup-actions>
261
+ ${post.editable
262
+ ? html `<md-text-button ?disabled=${this.busy} @click=${() => this.edit()}
263
+ >${t('gallery.button.edit')}</md-text-button
264
+ >
265
+ <md-text-button ?disabled=${this.busy} @click=${() => this.deletePost()}
266
+ >${t('gallery.button.delete')}</md-text-button
267
+ >`
268
+ : nothing}
269
+ ${post.moderatable && !this.hiding
270
+ ? post.hiddenAt
271
+ ? html `<md-text-button ?disabled=${this.busy} @click=${() => this.unhide()}
272
+ >${t('gallery.button.unhide')}</md-text-button
273
+ >`
274
+ : html `<md-text-button ?disabled=${this.busy} @click=${() => (this.hiding = true)}
275
+ >${t('gallery.button.hide')}</md-text-button
276
+ >`
277
+ : nothing}
278
+ ${this.hiding
279
+ ? html `<md-text-button slot="cancel" @click=${() => (this.hiding = false)}
280
+ >${t('gallery.button.cancel')}</md-text-button
281
+ >
282
+ <md-filled-button
283
+ slot="confirm"
284
+ ?disabled=${this.busy || !this.reason.trim()}
285
+ @click=${() => this.hide()}
286
+ >${t('gallery.button.hide')}</md-filled-button
287
+ >`
288
+ : html `<md-filled-button slot="confirm" @click=${() => this.close()}
289
+ >${t('gallery.button.close')}</md-filled-button
290
+ >`}
291
+ </ox-popup-actions>`;
292
+ }
293
+ replace(post) {
294
+ this.post = post;
295
+ this.index = Math.min(this.index, Math.max(0, post.photos.length - 1));
296
+ galleryChanged();
297
+ }
298
+ /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */
299
+ async like(like, fromPhoto = false) {
300
+ const post = this.post;
301
+ if (fromPhoto) {
302
+ this.burst++;
303
+ setTimeout(() => (this.burst = 0), 600);
304
+ if (post.liked)
305
+ return;
306
+ }
307
+ this.busy = true;
308
+ try {
309
+ const state = await galleryApi.like(post.id, like);
310
+ this.post = { ...post, likeCount: state.likeCount, liked: state.liked };
311
+ if (this.likers)
312
+ this.likers = await galleryApi.likers(post.id);
313
+ this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }));
314
+ }
315
+ catch (error) {
316
+ notify({ level: 'error', message: reasonOf(error) });
317
+ }
318
+ finally {
319
+ this.busy = false;
320
+ }
321
+ }
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
+ }
333
+ }
334
+ edit() {
335
+ this.close({ edit: this.post });
336
+ }
337
+ async deletePost() {
338
+ const sure = await OxPrompt.open({
339
+ title: t('gallery.button.delete'),
340
+ text: t('gallery.text.delete-confirm'),
341
+ confirmButton: { text: t('gallery.button.delete') },
342
+ cancelButton: { text: t('gallery.button.cancel') }
343
+ });
344
+ if (!sure)
345
+ return;
346
+ this.busy = true;
347
+ try {
348
+ await galleryApi.remove(this.post.id);
349
+ notify({ message: t('gallery.text.deleted') });
350
+ galleryChanged();
351
+ this.close();
352
+ }
353
+ catch (error) {
354
+ notify({ level: 'error', message: reasonOf(error) });
355
+ }
356
+ finally {
357
+ this.busy = false;
358
+ }
359
+ }
360
+ async hide() {
361
+ this.busy = true;
362
+ try {
363
+ const own = this.post.editable;
364
+ this.replace(await galleryApi.hide(this.post.id, this.reason.trim()));
365
+ this.hiding = false;
366
+ this.reason = '';
367
+ /* Its owner is told - unless the one hiding it is its owner. */
368
+ notify({ message: own ? t('gallery.text.hidden-own') : t('gallery.text.hidden-done') });
369
+ }
370
+ catch (error) {
371
+ notify({ level: 'error', message: reasonOf(error) });
372
+ }
373
+ finally {
374
+ this.busy = false;
375
+ }
376
+ }
377
+ async unhide() {
378
+ this.busy = true;
379
+ try {
380
+ this.replace(await galleryApi.unhide(this.post.id));
381
+ }
382
+ catch (error) {
383
+ notify({ level: 'error', message: reasonOf(error) });
384
+ }
385
+ finally {
386
+ this.busy = false;
387
+ }
388
+ }
389
+ go(address) {
390
+ this.close({ go: address });
391
+ }
392
+ /** 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. */
393
+ close(next) {
394
+ this.dispatchEvent(new CustomEvent('done', { detail: next, bubbles: true, composed: true }));
395
+ }
396
+ };
397
+ __decorate([
398
+ property({ attribute: false }),
399
+ __metadata("design:type", Object)
400
+ ], GalleryViewer.prototype, "post", void 0);
401
+ __decorate([
402
+ state(),
403
+ __metadata("design:type", Object)
404
+ ], GalleryViewer.prototype, "index", void 0);
405
+ __decorate([
406
+ state(),
407
+ __metadata("design:type", Array)
408
+ ], GalleryViewer.prototype, "likers", void 0);
409
+ __decorate([
410
+ state(),
411
+ __metadata("design:type", Object)
412
+ ], GalleryViewer.prototype, "hiding", void 0);
413
+ __decorate([
414
+ state(),
415
+ __metadata("design:type", Object)
416
+ ], GalleryViewer.prototype, "reason", void 0);
417
+ __decorate([
418
+ state(),
419
+ __metadata("design:type", Object)
420
+ ], GalleryViewer.prototype, "burst", void 0);
421
+ __decorate([
422
+ state(),
423
+ __metadata("design:type", Object)
424
+ ], GalleryViewer.prototype, "busy", void 0);
425
+ GalleryViewer = __decorate([
426
+ customElement('gallery-viewer')
427
+ ], GalleryViewer);
428
+ export { GalleryViewer };
429
+ //# sourceMappingURL=gallery-viewer.js.map
@@ -0,0 +1 @@
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 { 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"]}
@@ -0,0 +1 @@
1
+ export { generateGalleryBadge, refreshGalleryBadge } from './utils/gallery-badge.js';
@@ -0,0 +1,2 @@
1
+ export { generateGalleryBadge, refreshGalleryBadge } from './utils/gallery-badge.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA","sourcesContent":["export { generateGalleryBadge, refreshGalleryBadge } from './utils/gallery-badge.js'\n"]}