@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.
- package/dist-client/bootstrap.d.ts +2 -0
- package/dist-client/bootstrap.js +26 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/gallery-forms.d.ts +31 -0
- package/dist-client/components/gallery-forms.js +223 -0
- package/dist-client/components/gallery-forms.js.map +1 -0
- package/dist-client/components/gallery-saver-setting-let.d.ts +11 -0
- package/dist-client/components/gallery-saver-setting-let.js +81 -0
- package/dist-client/components/gallery-saver-setting-let.js.map +1 -0
- package/dist-client/components/gallery-show.d.ts +46 -0
- package/dist-client/components/gallery-show.js +316 -0
- package/dist-client/components/gallery-show.js.map +1 -0
- package/dist-client/components/gallery-uploader.d.ts +57 -0
- package/dist-client/components/gallery-uploader.js +624 -0
- package/dist-client/components/gallery-uploader.js.map +1 -0
- package/dist-client/components/gallery-viewer.d.ts +30 -0
- package/dist-client/components/gallery-viewer.js +429 -0
- package/dist-client/components/gallery-viewer.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/gallery-page.d.ts +54 -0
- package/dist-client/pages/gallery-page.js +590 -0
- package/dist-client/pages/gallery-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +9 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/utils/gallery-api.d.ts +99 -0
- package/dist-client/utils/gallery-api.js +46 -0
- package/dist-client/utils/gallery-api.js.map +1 -0
- package/dist-client/utils/gallery-badge.d.ts +4 -0
- package/dist-client/utils/gallery-badge.js +45 -0
- package/dist-client/utils/gallery-badge.js.map +1 -0
- package/dist-client/utils/gallery-saver.d.ts +6 -0
- package/dist-client/utils/gallery-saver.js +69 -0
- package/dist-client/utils/gallery-saver.js.map +1 -0
- package/dist-client/utils/gallery-words.d.ts +7 -0
- package/dist-client/utils/gallery-words.js +20 -0
- package/dist-client/utils/gallery-words.js.map +1 -0
- package/dist-client/utils/photo-prep.d.ts +10 -0
- package/dist-client/utils/photo-prep.js +102 -0
- package/dist-client/utils/photo-prep.js.map +1 -0
- package/dist-server/attachment-reader.d.ts +1 -0
- package/dist-server/attachment-reader.js +13 -0
- package/dist-server/attachment-reader.js.map +1 -0
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +11 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +15 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/gallery/gallery-resolver.d.ts +29 -0
- package/dist-server/service/gallery/gallery-resolver.js +613 -0
- package/dist-server/service/gallery/gallery-resolver.js.map +1 -0
- package/dist-server/service/gallery/gallery-rules.d.ts +90 -0
- package/dist-server/service/gallery/gallery-rules.js +182 -0
- package/dist-server/service/gallery/gallery-rules.js.map +1 -0
- package/dist-server/service/gallery/gallery-service.d.ts +37 -0
- package/dist-server/service/gallery/gallery-service.js +234 -0
- package/dist-server/service/gallery/gallery-service.js.map +1 -0
- package/dist-server/service/gallery/gallery-types.d.ts +65 -0
- package/dist-server/service/gallery/gallery-types.js +239 -0
- package/dist-server/service/gallery/gallery-types.js.map +1 -0
- package/dist-server/service/gallery/gallery.d.ts +84 -0
- package/dist-server/service/gallery/gallery.js +335 -0
- package/dist-server/service/gallery/gallery.js.map +1 -0
- package/dist-server/service/gallery/index.d.ts +4 -0
- package/dist-server/service/gallery/index.js +8 -0
- package/dist-server/service/gallery/index.js.map +1 -0
- package/dist-server/service/index.d.ts +7 -0
- package/dist-server/service/index.js +23 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- 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":";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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { generateGalleryBadge, refreshGalleryBadge } from './utils/gallery-badge.js';
|
|
@@ -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"]}
|