@things-factory/gallery 10.1.256 → 10.1.258
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/components/gallery-uploader.ts +16 -8
- package/client/components/gallery-viewer.ts +16 -12
- package/client/utils/gallery-api.ts +0 -6
- package/dist-client/components/gallery-uploader.d.ts +4 -1
- package/dist-client/components/gallery-uploader.js +13 -11
- package/dist-client/components/gallery-uploader.js.map +1 -1
- package/dist-client/components/gallery-viewer.d.ts +4 -1
- package/dist-client/components/gallery-viewer.js +16 -15
- package/dist-client/components/gallery-viewer.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/gallery-api.d.ts +0 -4
- package/dist-client/utils/gallery-api.js +0 -1
- package/dist-client/utils/gallery-api.js.map +1 -1
- package/package.json +12 -12
|
@@ -10,9 +10,12 @@ import '@operato/input/ox-input-file.js'
|
|
|
10
10
|
import '@operato/input/ox-input-select-buttons.js'
|
|
11
11
|
import '@operato/popup/ox-popup-actions.js'
|
|
12
12
|
|
|
13
|
+
import gql from 'graphql-tag'
|
|
13
14
|
import { css, html, LitElement, nothing } from 'lit'
|
|
14
15
|
import { customElement, property, query, state } from 'lit/decorators.js'
|
|
15
16
|
|
|
17
|
+
import { QueryController } from '@operato/graphql'
|
|
18
|
+
|
|
16
19
|
import { i18next, localize } from '@operato/i18n'
|
|
17
20
|
import { notify } from '@operato/layout'
|
|
18
21
|
import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'
|
|
@@ -226,7 +229,8 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
|
|
|
226
229
|
@state() private tagText = ''
|
|
227
230
|
/** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
|
|
228
231
|
@state() private tagRefusal = ''
|
|
229
|
-
|
|
232
|
+
/** The tag text the suggestions are for - the typed text once typing pauses. */
|
|
233
|
+
@state() private suggestFor?: string
|
|
230
234
|
@state() private chosenSpace: Space = 'COMPANY'
|
|
231
235
|
/** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
|
|
232
236
|
@state() private shared = false
|
|
@@ -242,6 +246,16 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
|
|
|
242
246
|
|
|
243
247
|
private suggestTimer?: ReturnType<typeof setTimeout>
|
|
244
248
|
|
|
249
|
+
/* The tags used before that begin like the one typed; the last ones stay while the next are read. */
|
|
250
|
+
private suggestionsRead = new QueryController(this, gql`query ($text: String) { galleryTags(text: $text) { tag count } }`, {
|
|
251
|
+
variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),
|
|
252
|
+
keepPrevious: true
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
private get suggestions(): { tag: string; count: number }[] {
|
|
256
|
+
return this.suggestionsRead.data?.galleryTags ?? []
|
|
257
|
+
}
|
|
258
|
+
|
|
245
259
|
render() {
|
|
246
260
|
const total = this.kept.length + this.added.length
|
|
247
261
|
const full = total >= MAX_PHOTOS
|
|
@@ -507,13 +521,7 @@ export class GalleryUploader extends localize(i18next)(LitElement) {
|
|
|
507
521
|
}
|
|
508
522
|
this.tagText = value
|
|
509
523
|
clearTimeout(this.suggestTimer)
|
|
510
|
-
this.suggestTimer = setTimeout(
|
|
511
|
-
try {
|
|
512
|
-
this.suggestions = await galleryApi.tags(this.tagText)
|
|
513
|
-
} catch {
|
|
514
|
-
this.suggestions = []
|
|
515
|
-
}
|
|
516
|
-
}, 200)
|
|
524
|
+
this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200)
|
|
517
525
|
}
|
|
518
526
|
|
|
519
527
|
private tagKey(e: KeyboardEvent) {
|
|
@@ -9,9 +9,12 @@ import '@material/web/button/text-button.js'
|
|
|
9
9
|
import '@material/web/icon/icon.js'
|
|
10
10
|
import '@operato/popup/ox-popup-actions.js'
|
|
11
11
|
|
|
12
|
+
import gql from 'graphql-tag'
|
|
12
13
|
import { css, html, LitElement, nothing } from 'lit'
|
|
13
14
|
import { customElement, property, state } from 'lit/decorators.js'
|
|
14
15
|
|
|
16
|
+
import { QueryController } from '@operato/graphql'
|
|
17
|
+
|
|
15
18
|
import { i18next, localize } from '@operato/i18n'
|
|
16
19
|
import { notify } from '@operato/layout'
|
|
17
20
|
import { OxPrompt } from '@operato/popup/ox-prompt.js'
|
|
@@ -195,12 +198,21 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
195
198
|
@property({ attribute: false }) post!: Post
|
|
196
199
|
|
|
197
200
|
@state() private index = 0
|
|
198
|
-
|
|
201
|
+
/** Who liked it is shown under the heart once asked. */
|
|
202
|
+
@state() private showingLikers = false
|
|
199
203
|
@state() private hiding = false
|
|
200
204
|
@state() private reason = ''
|
|
201
205
|
@state() private burst = 0
|
|
202
206
|
@state() private busy = false
|
|
203
207
|
|
|
208
|
+
private likersRead = new QueryController(this, gql`query ($id: String!) { galleryLikers(id: $id) { id name } }`, {
|
|
209
|
+
variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
private get likers(): { id: string; name?: string }[] | undefined {
|
|
213
|
+
return this.likersRead.data?.galleryLikers
|
|
214
|
+
}
|
|
215
|
+
|
|
204
216
|
render() {
|
|
205
217
|
const post = this.post
|
|
206
218
|
if (!post) return nothing
|
|
@@ -326,7 +338,7 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
326
338
|
try {
|
|
327
339
|
const state = await galleryApi.like(post.id, like)
|
|
328
340
|
this.post = { ...post, likeCount: state.likeCount, liked: state.liked }
|
|
329
|
-
if (this.
|
|
341
|
+
if (this.showingLikers) this.likersRead.refetch()
|
|
330
342
|
this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }))
|
|
331
343
|
} catch (error) {
|
|
332
344
|
notify({ level: 'error', message: reasonOf(error) })
|
|
@@ -335,16 +347,8 @@ export class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
335
347
|
}
|
|
336
348
|
}
|
|
337
349
|
|
|
338
|
-
private
|
|
339
|
-
|
|
340
|
-
this.likers = undefined
|
|
341
|
-
return
|
|
342
|
-
}
|
|
343
|
-
try {
|
|
344
|
-
this.likers = await galleryApi.likers(this.post.id)
|
|
345
|
-
} catch (error) {
|
|
346
|
-
notify({ level: 'error', message: reasonOf(error) })
|
|
347
|
-
}
|
|
350
|
+
private showLikers() {
|
|
351
|
+
this.showingLikers = !this.showingLikers
|
|
348
352
|
}
|
|
349
353
|
|
|
350
354
|
private edit() {
|
|
@@ -82,12 +82,6 @@ export const galleryApi = {
|
|
|
82
82
|
),
|
|
83
83
|
post: (id: string) =>
|
|
84
84
|
ask<Post | null>(`query ($id: String!) { galleryPost(id: $id) { ${POST_FIELDS} } }`, { id }, 'galleryPost'),
|
|
85
|
-
likers: (id: string) =>
|
|
86
|
-
ask<{ id: string; name?: string }[]>(
|
|
87
|
-
`query ($id: String!) { galleryLikers(id: $id) { id name } }`,
|
|
88
|
-
{ id },
|
|
89
|
-
'galleryLikers'
|
|
90
|
-
),
|
|
91
85
|
tags: (text = '') =>
|
|
92
86
|
ask<{ tag: string; count: number }[]>(
|
|
93
87
|
`query ($text: String) { galleryTags(text: $text) { tag count } }`,
|
|
@@ -23,7 +23,8 @@ export declare class GalleryUploader extends GalleryUploader_base {
|
|
|
23
23
|
private tagText;
|
|
24
24
|
/** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
|
|
25
25
|
private tagRefusal;
|
|
26
|
-
|
|
26
|
+
/** The tag text the suggestions are for - the typed text once typing pauses. */
|
|
27
|
+
private suggestFor?;
|
|
27
28
|
private chosenSpace;
|
|
28
29
|
/** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
|
|
29
30
|
private shared;
|
|
@@ -36,6 +37,8 @@ export declare class GalleryUploader extends GalleryUploader_base {
|
|
|
36
37
|
private picker;
|
|
37
38
|
private camera;
|
|
38
39
|
private suggestTimer?;
|
|
40
|
+
private suggestionsRead;
|
|
41
|
+
private get suggestions();
|
|
39
42
|
render(): import("lit-html").TemplateResult<1>;
|
|
40
43
|
private choiceChip;
|
|
41
44
|
firstUpdated(): Promise<void>;
|
|
@@ -10,8 +10,10 @@ import '@material/web/icon/icon.js';
|
|
|
10
10
|
import '@operato/input/ox-input-file.js';
|
|
11
11
|
import '@operato/input/ox-input-select-buttons.js';
|
|
12
12
|
import '@operato/popup/ox-popup-actions.js';
|
|
13
|
+
import gql from 'graphql-tag';
|
|
13
14
|
import { css, html, LitElement, nothing } from 'lit';
|
|
14
15
|
import { customElement, property, query, state } from 'lit/decorators.js';
|
|
16
|
+
import { QueryController } from '@operato/graphql';
|
|
15
17
|
import { i18next, localize } from '@operato/i18n';
|
|
16
18
|
import { notify } from '@operato/layout';
|
|
17
19
|
import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles';
|
|
@@ -41,7 +43,6 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
|
|
|
41
43
|
this.tagText = '';
|
|
42
44
|
/** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */
|
|
43
45
|
this.tagRefusal = '';
|
|
44
|
-
this.suggestions = [];
|
|
45
46
|
this.chosenSpace = 'COMPANY';
|
|
46
47
|
/** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */
|
|
47
48
|
this.shared = false;
|
|
@@ -50,6 +51,11 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
|
|
|
50
51
|
this.choices = [];
|
|
51
52
|
this.allChoices = false;
|
|
52
53
|
this.busy = false;
|
|
54
|
+
/* The tags used before that begin like the one typed; the last ones stay while the next are read. */
|
|
55
|
+
this.suggestionsRead = new QueryController(this, gql `query ($text: String) { galleryTags(text: $text) { tag count } }`, {
|
|
56
|
+
variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),
|
|
57
|
+
keepPrevious: true
|
|
58
|
+
});
|
|
53
59
|
}
|
|
54
60
|
static { this.styles = [
|
|
55
61
|
CommonPopupStyles,
|
|
@@ -217,6 +223,9 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
|
|
|
217
223
|
}
|
|
218
224
|
`
|
|
219
225
|
]; }
|
|
226
|
+
get suggestions() {
|
|
227
|
+
return this.suggestionsRead.data?.galleryTags ?? [];
|
|
228
|
+
}
|
|
220
229
|
render() {
|
|
221
230
|
const total = this.kept.length + this.added.length;
|
|
222
231
|
const full = total >= MAX_PHOTOS;
|
|
@@ -464,14 +473,7 @@ let GalleryUploader = class GalleryUploader extends localize(i18next)(LitElement
|
|
|
464
473
|
}
|
|
465
474
|
this.tagText = value;
|
|
466
475
|
clearTimeout(this.suggestTimer);
|
|
467
|
-
this.suggestTimer = setTimeout(
|
|
468
|
-
try {
|
|
469
|
-
this.suggestions = await galleryApi.tags(this.tagText);
|
|
470
|
-
}
|
|
471
|
-
catch {
|
|
472
|
-
this.suggestions = [];
|
|
473
|
-
}
|
|
474
|
-
}, 200);
|
|
476
|
+
this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200);
|
|
475
477
|
}
|
|
476
478
|
tagKey(e) {
|
|
477
479
|
if (e.isComposing)
|
|
@@ -575,8 +577,8 @@ __decorate([
|
|
|
575
577
|
], GalleryUploader.prototype, "tagRefusal", void 0);
|
|
576
578
|
__decorate([
|
|
577
579
|
state(),
|
|
578
|
-
__metadata("design:type",
|
|
579
|
-
], GalleryUploader.prototype, "
|
|
580
|
+
__metadata("design:type", String)
|
|
581
|
+
], GalleryUploader.prototype, "suggestFor", void 0);
|
|
580
582
|
__decorate([
|
|
581
583
|
state(),
|
|
582
584
|
__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gallery-uploader.js","sourceRoot":"","sources":["../../client/components/gallery-uploader.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Posting photos (ADR-0165 decision 3) - and changing one's own post. Photos are all it needs; the caption, the tags\n * and the event are there to add. When the photos were taken is read from the first one, and the events near that day\n * are offered first - one press puts the post on one.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-file.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport {\n galleryApi,\n galleryChanged,\n type EventChoice,\n type Photo,\n type Post,\n type Space\n} from '../utils/gallery-api.js'\nimport { day, reasonOf, t } from '../utils/gallery-words.js'\nimport { shrunk, takenAtOf } from '../utils/photo-prep.js'\n\nconst MAX_PHOTOS = 20\nconst MAX_CAPTION = 500\nconst MAX_TAGS = 10\nconst MAX_TAG = 30\n/* The events shown before 「more」 - the near ones are among them. */\nconst FIRST_CHOICES = 4\n\ntype Added = { file: File; url: string }\n\n/** yyyy-mm-dd of a date in the reader's own time. */\nconst dateText = (value: Date) =>\n `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`\n\n@customElement('gallery-uploader')\nexport class GalleryUploader extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n }\n h4 {\n margin: 0 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .photos {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));\n gap: var(--spacing-small, 4px);\n }\n .photo {\n position: relative;\n aspect-ratio: 1;\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n background: var(--md-sys-color-surface-container-high);\n }\n .photo img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n .photo button {\n position: absolute;\n top: 2px;\n inset-inline-end: 2px;\n display: inline-flex;\n padding: 2px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n cursor: pointer;\n }\n .photo button md-icon {\n --md-icon-size: 16px;\n }\n .add {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n aspect-ratio: 1;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline));\n border-radius: var(--border-radius, 4px);\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n }\n .add[disabled] {\n opacity: 0.4;\n cursor: default;\n }\n ox-input-file {\n display: contents;\n }\n textarea,\n input {\n box-sizing: border-box;\n width: 100%;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n textarea {\n min-height: 64px;\n resize: vertical;\n }\n input[type='date'] {\n width: auto;\n }\n .count {\n text-align: end;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .refusal {\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-error);\n }\n .chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n border-radius: 999px;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n line-height: 1.6;\n cursor: pointer;\n }\n .chip[aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .chip .near {\n color: var(--md-sys-color-primary);\n }\n .tag-input {\n flex: 1;\n min-width: 120px;\n width: auto;\n border: 0;\n padding: 2px 0;\n background: none;\n }\n .tag-input:focus {\n outline: none;\n }\n .tags {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n }\n .suggest {\n margin-top: var(--spacing-small, 4px);\n }\n .suggest .chip {\n border-style: dashed;\n }\n .muted {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-large, 12px);\n align-items: flex-end;\n }\n `\n ]\n\n /** The post being changed - nothing when posting a new one. */\n @property({ attribute: false }) post?: Post\n /** The photos the page picked before the window opened. */\n @property({ attribute: false }) files: File[] = []\n /** Where a new post goes - the screen it was opened from. */\n @property() space: Space = 'COMPANY'\n @property() eventId?: string | null\n\n @state() private added: Added[] = []\n @state() private kept: Photo[] = []\n @state() private caption = ''\n @state() private tags: string[] = []\n @state() private tagText = ''\n /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */\n @state() private tagRefusal = ''\n @state() private suggestions: { tag: string; count: number }[] = []\n @state() private chosenSpace: Space = 'COMPANY'\n /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */\n @state() private shared = false\n @state() private chosenEvent: string | null = null\n @state() private takenOn = dateText(new Date())\n @state() private choices: EventChoice[] = []\n @state() private allChoices = false\n @state() private progress?: number\n @state() private busy = false\n\n @query('#pick') private picker!: any\n @query('#shoot') private camera!: any\n\n private suggestTimer?: ReturnType<typeof setTimeout>\n\n render() {\n const total = this.kept.length + this.added.length\n const full = total >= MAX_PHOTOS\n const company = this.chosenSpace === 'COMPANY'\n const shown = this.allChoices ? this.choices : this.choices.slice(0, FIRST_CHOICES)\n const chosen = this.choices.find(one => one.id === this.chosenEvent)\n return html`<div class=\"body\">\n <section>\n <div class=\"photos\">\n ${this.kept.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.thumbnail || one.fullpath} alt=\"\" />\n <button\n aria-label=${t('gallery.button.remove-photo')}\n @click=${() => (this.kept = this.kept.filter(other => other !== one))}\n >\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n ${this.added.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.url} alt=\"\" />\n <button aria-label=${t('gallery.button.remove-photo')} @click=${() => this.drop(one)}>\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n <button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.picker?.pick()}>\n <md-icon>add_photo_alternate</md-icon>${t('gallery.button.add-photos')}\n </button>\n ${\n isMobileDevice()\n ? html`<button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.camera?.pick()}>\n <md-icon>photo_camera</md-icon>${t('gallery.button.shoot-more')}\n </button>`\n : nothing\n }\n </div>\n <ox-input-file\n id=\"pick\"\n quiet\n outside-trigger\n hide-filelist\n multiple\n accept=\"image/*\"\n .progress=${this.progress}\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n <ox-input-file\n id=\"shoot\"\n quiet\n outside-trigger\n hide-filelist\n accept=\"image/*\"\n capture=\"environment\"\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n ${full ? html`<div class=\"muted\">${t('gallery.text.photos-full', { count: MAX_PHOTOS })}</div>` : nothing}\n </section>\n\n <section>\n <textarea\n maxlength=${MAX_CAPTION}\n placeholder=${t('gallery.text.caption-placeholder')}\n .value=${this.caption}\n @input=${(e: any) => (this.caption = e.target.value)}\n ></textarea>\n ${this.caption.length > MAX_CAPTION * 0.8 ? html`<div class=\"count\">${this.caption.length} / ${MAX_CAPTION}</div>` : nothing}\n </section>\n\n <section>\n <h4>${t('gallery.field.tags')}</h4>\n <div class=\"chips tags\">\n ${this.tags.map(tag => html`<span class=\"chip\">#${tag}<md-icon role=\"button\" aria-label=${t('gallery.button.remove-tag')} @click=${() => (this.tags = this.tags.filter(one => one !== tag))}>close</md-icon></span>`)}\n ${\n this.tags.length < MAX_TAGS\n ? html`<input\n class=\"tag-input\"\n .value=${this.tagText}\n placeholder=${this.tags.length ? '' : t('gallery.text.tag-placeholder')}\n @input=${(e: any) => this.typeTag(e.target.value)}\n @keydown=${(e: KeyboardEvent) => this.tagKey(e)}\n @blur=${() => this.addTag(this.tagText)}\n />`\n : nothing\n }\n </div>\n ${this.tagRefusal ? html`<div class=\"refusal\" role=\"alert\">${this.tagRefusal}</div>` : nothing}\n ${\n this.suggestions.length\n ? html`<div class=\"chips suggest\">\n ${this.suggestions.filter(one => !this.tags.some(tag => tag.toLowerCase() === one.tag.toLowerCase())).map(one => html`<button class=\"chip\" @mousedown=${(e: Event) => e.preventDefault()} @click=${() => this.addTag(one.tag)}>#${one.tag}</button>`)}\n </div>`\n : nothing\n }\n </section>\n\n <section class=\"row\">\n <div>\n <h4>${t('gallery.field.space')}</h4>\n <ox-input-select-buttons\n .options=${(['COMPANY', 'PERSONAL'] as Space[]).map(space => ({ value: space, display: t(`gallery.space.${space}`) }))}\n .value=${this.chosenSpace}\n @change=${(e: CustomEvent) => (e.detail ? this.chooseSpace(e.detail as Space) : ((e.target as any).value = this.chosenSpace))}\n ></ox-input-select-buttons>\n </div>\n <div>\n <h4>${t('gallery.field.taken-on')}</h4>\n <input type=\"date\" .value=${this.takenOn} @change=${(e: any) => this.changeDay(e.target.value)} />\n </div>\n </section>\n\n ${\n company\n ? html`<section>\n <h4>${t('gallery.field.event')}</h4>\n <div class=\"chips\">\n <button\n class=\"chip\"\n aria-pressed=${String(!this.chosenEvent)}\n @click=${() => (this.chosenEvent = null)}\n >\n ${t('gallery.text.no-event')}\n </button>\n ${chosen && !shown.includes(chosen) ? this.choiceChip(chosen) : nothing}\n ${shown.map(one => this.choiceChip(one))}\n ${\n this.choices.length > FIRST_CHOICES && !this.allChoices\n ? html`<button class=\"chip\" @click=${() => (this.allChoices = true)}>\n ${t('gallery.button.more-events', { count: this.choices.length - FIRST_CHOICES })}\n </button>`\n : nothing\n }\n </div>\n </section>`\n : html`<section>\n <h4>${t('gallery.field.shared')}</h4>\n <ox-input-select-buttons\n .options=${[\n { value: 'me', display: t('gallery.text.only-me') },\n { value: 'everyone', display: t('gallery.text.everyone') }\n ]}\n .value=${this.shared ? 'everyone' : 'me'}\n @change=${(e: CustomEvent) => (e.detail ? (this.shared = e.detail === 'everyone') : ((e.target as any).value = this.shared ? 'everyone' : 'me'))}\n ></ox-input-select-buttons>\n <div class=\"muted\">${t(this.shared ? 'gallery.text.shared-note' : 'gallery.text.only-me-note')}</div>\n </section>`\n }\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" ?disabled=${this.busy} @click=${() => this.close()}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || total < 1} @click=${() => this.save()}\n >${this.post ? t('gallery.button.save') : t('gallery.button.post-count', { count: total })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private choiceChip(one: EventChoice) {\n return html`<button\n class=\"chip\"\n aria-pressed=${String(this.chosenEvent === one.id)}\n @click=${() => (this.chosenEvent = one.id)}\n >\n ${one.near ? html`<md-icon class=\"near\">event_available</md-icon>` : nothing}${one.name}<span class=\"muted\"\n >· ${day(one.startAt)}</span\n >\n </button>`\n }\n\n async firstUpdated() {\n const post = this.post\n if (post) {\n this.kept = [...post.photos]\n this.caption = post.caption ?? ''\n this.tags = [...(post.tags ?? [])]\n this.chosenSpace = post.space\n this.shared = post.shared\n this.chosenEvent = post.event?.id ?? null\n this.takenOn = dateText(new Date(post.takenAt))\n } else {\n this.chosenSpace = this.eventId ? 'COMPANY' : this.space\n this.chosenEvent = this.eventId ?? null\n }\n await this.add(this.files ?? [])\n await this.loadChoices()\n }\n\n disconnectedCallback() {\n for (const one of this.added) URL.revokeObjectURL(one.url)\n clearTimeout(this.suggestTimer)\n super.disconnectedCallback()\n }\n\n private async take(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n const before = this.kept.length + this.added.length\n await this.add(picked)\n /* The first photo says the day - the events near it come first. */\n if (!before && !this.post) await this.loadChoices()\n }\n\n private async add(files: File[]) {\n const room = MAX_PHOTOS - this.kept.length - this.added.length\n const photos = files\n .filter(file => /^image\\//i.test(file.type) || /\\.(jpe?g|png|gif|webp|heic|heif)$/i.test(file.name))\n .slice(0, Math.max(0, room))\n if (photos.length < files.length)\n notify({ level: 'warn', message: t('gallery.text.photos-skipped', { count: files.length - photos.length }) })\n if (!photos.length) return\n const first = !this.kept.length && !this.added.length && !this.post\n this.added = [...this.added, ...photos.map(file => ({ file, url: URL.createObjectURL(file) }))]\n if (first) {\n const takenAt = await takenAtOf(photos[0])\n if (takenAt) this.takenOn = dateText(takenAt)\n }\n }\n\n private drop(one: Added) {\n URL.revokeObjectURL(one.url)\n this.added = this.added.filter(other => other !== one)\n }\n\n private takenAt(): string {\n const [y, m, d] = this.takenOn.split('-').map(Number)\n const now = new Date()\n /* A day chosen without its hour keeps the hour it was posted - today's photo is not dated midnight. */\n const at = y ? new Date(y, m - 1, d, now.getHours(), now.getMinutes()) : now\n return at.toISOString()\n }\n\n private async loadChoices() {\n try {\n /* Offered, not chosen: the events near that day come first, and one press puts the post on one. */\n this.choices = await galleryApi.eventChoices(this.takenAt())\n } catch {\n this.choices = []\n }\n }\n\n private async changeDay(value: string) {\n if (!value) return\n this.takenOn = value\n await this.loadChoices()\n }\n\n private chooseSpace(space: Space) {\n this.chosenSpace = space\n if (space === 'PERSONAL') this.chosenEvent = null\n }\n\n private typeTag(value: string) {\n if (/[,\\s]$/.test(value) && value.trim()) {\n this.addTag(value)\n return\n }\n this.tagText = value\n clearTimeout(this.suggestTimer)\n this.suggestTimer = setTimeout(async () => {\n try {\n this.suggestions = await galleryApi.tags(this.tagText)\n } catch {\n this.suggestions = []\n }\n }, 200)\n }\n\n private tagKey(e: KeyboardEvent) {\n if (e.isComposing) return\n if (e.key === 'Enter') {\n e.preventDefault()\n this.addTag(this.tagText)\n } else if (e.key === 'Backspace' && !this.tagText && this.tags.length) {\n this.tags = this.tags.slice(0, -1)\n }\n }\n\n /** Takes the typed tag, or says why not and keeps it - a longer tag was cut at 30 without a word (2026-10-30). */\n private addTag(raw: string): boolean {\n const tag = raw.replace(/[,]/g, ' ').trim().replace(/^#+/, '').replace(/\\s+/g, ' ').trim()\n if (tag.length > MAX_TAG) {\n this.tagRefusal = t('gallery.text.tag-too-long-typed', { max: MAX_TAG, length: tag.length })\n return false\n }\n this.tagRefusal = ''\n this.tagText = ''\n if (!tag || this.tags.length >= MAX_TAGS || this.tags.some(one => one.toLowerCase() === tag.toLowerCase())) return true\n this.tags = [...this.tags, tag]\n return true\n }\n\n private async save() {\n if (!this.addTag(this.tagText)) return\n this.busy = true\n try {\n const files = await Promise.all(this.added.map(one => shrunk(one.file)))\n const input = {\n space: this.chosenSpace,\n shared: this.chosenSpace === 'PERSONAL' && this.shared,\n caption: this.caption.trim(),\n takenAt: this.takenAt(),\n tags: this.tags,\n eventId: this.chosenSpace === 'COMPANY' ? this.chosenEvent : null\n }\n const uploading = (fraction: number) => (this.progress = fraction)\n const post = this.post\n ? await galleryApi.update(\n this.post.id,\n input,\n files,\n this.post.photos.filter(one => !this.kept.includes(one)).map(one => one.id),\n uploading\n )\n : await galleryApi.create(input, files, uploading)\n notify({ message: this.post ? t('gallery.text.saved') : t('gallery.text.posted') })\n galleryChanged()\n this.dispatchEvent(new CustomEvent('gallery-posted', { detail: post, bubbles: true, composed: true }))\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.progress = undefined\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"gallery-uploader.js","sourceRoot":"","sources":["../../client/components/gallery-uploader.ts"],"names":[],"mappings":"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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 gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport {\n galleryApi,\n galleryChanged,\n type EventChoice,\n type Photo,\n type Post,\n type Space\n} from '../utils/gallery-api.js'\nimport { day, reasonOf, t } from '../utils/gallery-words.js'\nimport { shrunk, takenAtOf } from '../utils/photo-prep.js'\n\nconst MAX_PHOTOS = 20\nconst MAX_CAPTION = 500\nconst MAX_TAGS = 10\nconst MAX_TAG = 30\n/* The events shown before 「more」 - the near ones are among them. */\nconst FIRST_CHOICES = 4\n\ntype Added = { file: File; url: string }\n\n/** yyyy-mm-dd of a date in the reader's own time. */\nconst dateText = (value: Date) =>\n `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`\n\n@customElement('gallery-uploader')\nexport class GalleryUploader extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n }\n h4 {\n margin: 0 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .photos {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));\n gap: var(--spacing-small, 4px);\n }\n .photo {\n position: relative;\n aspect-ratio: 1;\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n background: var(--md-sys-color-surface-container-high);\n }\n .photo img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n .photo button {\n position: absolute;\n top: 2px;\n inset-inline-end: 2px;\n display: inline-flex;\n padding: 2px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n cursor: pointer;\n }\n .photo button md-icon {\n --md-icon-size: 16px;\n }\n .add {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n aspect-ratio: 1;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline));\n border-radius: var(--border-radius, 4px);\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n }\n .add[disabled] {\n opacity: 0.4;\n cursor: default;\n }\n ox-input-file {\n display: contents;\n }\n textarea,\n input {\n box-sizing: border-box;\n width: 100%;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n textarea {\n min-height: 64px;\n resize: vertical;\n }\n input[type='date'] {\n width: auto;\n }\n .count {\n text-align: end;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .refusal {\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-error);\n }\n .chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n border-radius: 999px;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n line-height: 1.6;\n cursor: pointer;\n }\n .chip[aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .chip .near {\n color: var(--md-sys-color-primary);\n }\n .tag-input {\n flex: 1;\n min-width: 120px;\n width: auto;\n border: 0;\n padding: 2px 0;\n background: none;\n }\n .tag-input:focus {\n outline: none;\n }\n .tags {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n }\n .suggest {\n margin-top: var(--spacing-small, 4px);\n }\n .suggest .chip {\n border-style: dashed;\n }\n .muted {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-large, 12px);\n align-items: flex-end;\n }\n `\n ]\n\n /** The post being changed - nothing when posting a new one. */\n @property({ attribute: false }) post?: Post\n /** The photos the page picked before the window opened. */\n @property({ attribute: false }) files: File[] = []\n /** Where a new post goes - the screen it was opened from. */\n @property() space: Space = 'COMPANY'\n @property() eventId?: string | null\n\n @state() private added: Added[] = []\n @state() private kept: Photo[] = []\n @state() private caption = ''\n @state() private tags: string[] = []\n @state() private tagText = ''\n /** Why the tag being typed was not taken - said under the tags, the text kept so it can be shortened. */\n @state() private tagRefusal = ''\n /** The tag text the suggestions are for - the typed text once typing pauses. */\n @state() private suggestFor?: string\n @state() private chosenSpace: Space = 'COMPANY'\n /** A post of the own gallery is the person's alone until shared (decision 2) - off when posting. */\n @state() private shared = false\n @state() private chosenEvent: string | null = null\n @state() private takenOn = dateText(new Date())\n @state() private choices: EventChoice[] = []\n @state() private allChoices = false\n @state() private progress?: number\n @state() private busy = false\n\n @query('#pick') private picker!: any\n @query('#shoot') private camera!: any\n\n private suggestTimer?: ReturnType<typeof setTimeout>\n\n /* The tags used before that begin like the one typed; the last ones stay while the next are read. */\n private suggestionsRead = new QueryController(this, gql`query ($text: String) { galleryTags(text: $text) { tag count } }`, {\n variables: () => (this.suggestFor === undefined ? undefined : { text: this.suggestFor }),\n keepPrevious: true\n })\n\n private get suggestions(): { tag: string; count: number }[] {\n return this.suggestionsRead.data?.galleryTags ?? []\n }\n\n render() {\n const total = this.kept.length + this.added.length\n const full = total >= MAX_PHOTOS\n const company = this.chosenSpace === 'COMPANY'\n const shown = this.allChoices ? this.choices : this.choices.slice(0, FIRST_CHOICES)\n const chosen = this.choices.find(one => one.id === this.chosenEvent)\n return html`<div class=\"body\">\n <section>\n <div class=\"photos\">\n ${this.kept.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.thumbnail || one.fullpath} alt=\"\" />\n <button\n aria-label=${t('gallery.button.remove-photo')}\n @click=${() => (this.kept = this.kept.filter(other => other !== one))}\n >\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n ${this.added.map(\n one =>\n html`<div class=\"photo\">\n <img src=${one.url} alt=\"\" />\n <button aria-label=${t('gallery.button.remove-photo')} @click=${() => this.drop(one)}>\n <md-icon>close</md-icon>\n </button>\n </div>`\n )}\n <button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.picker?.pick()}>\n <md-icon>add_photo_alternate</md-icon>${t('gallery.button.add-photos')}\n </button>\n ${\n isMobileDevice()\n ? html`<button class=\"add\" ?disabled=${full || this.busy} @click=${() => this.camera?.pick()}>\n <md-icon>photo_camera</md-icon>${t('gallery.button.shoot-more')}\n </button>`\n : nothing\n }\n </div>\n <ox-input-file\n id=\"pick\"\n quiet\n outside-trigger\n hide-filelist\n multiple\n accept=\"image/*\"\n .progress=${this.progress}\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n <ox-input-file\n id=\"shoot\"\n quiet\n outside-trigger\n hide-filelist\n accept=\"image/*\"\n capture=\"environment\"\n @change=${(e: CustomEvent) => this.take(e)}\n ></ox-input-file>\n ${full ? html`<div class=\"muted\">${t('gallery.text.photos-full', { count: MAX_PHOTOS })}</div>` : nothing}\n </section>\n\n <section>\n <textarea\n maxlength=${MAX_CAPTION}\n placeholder=${t('gallery.text.caption-placeholder')}\n .value=${this.caption}\n @input=${(e: any) => (this.caption = e.target.value)}\n ></textarea>\n ${this.caption.length > MAX_CAPTION * 0.8 ? html`<div class=\"count\">${this.caption.length} / ${MAX_CAPTION}</div>` : nothing}\n </section>\n\n <section>\n <h4>${t('gallery.field.tags')}</h4>\n <div class=\"chips tags\">\n ${this.tags.map(tag => html`<span class=\"chip\">#${tag}<md-icon role=\"button\" aria-label=${t('gallery.button.remove-tag')} @click=${() => (this.tags = this.tags.filter(one => one !== tag))}>close</md-icon></span>`)}\n ${\n this.tags.length < MAX_TAGS\n ? html`<input\n class=\"tag-input\"\n .value=${this.tagText}\n placeholder=${this.tags.length ? '' : t('gallery.text.tag-placeholder')}\n @input=${(e: any) => this.typeTag(e.target.value)}\n @keydown=${(e: KeyboardEvent) => this.tagKey(e)}\n @blur=${() => this.addTag(this.tagText)}\n />`\n : nothing\n }\n </div>\n ${this.tagRefusal ? html`<div class=\"refusal\" role=\"alert\">${this.tagRefusal}</div>` : nothing}\n ${\n this.suggestions.length\n ? html`<div class=\"chips suggest\">\n ${this.suggestions.filter(one => !this.tags.some(tag => tag.toLowerCase() === one.tag.toLowerCase())).map(one => html`<button class=\"chip\" @mousedown=${(e: Event) => e.preventDefault()} @click=${() => this.addTag(one.tag)}>#${one.tag}</button>`)}\n </div>`\n : nothing\n }\n </section>\n\n <section class=\"row\">\n <div>\n <h4>${t('gallery.field.space')}</h4>\n <ox-input-select-buttons\n .options=${(['COMPANY', 'PERSONAL'] as Space[]).map(space => ({ value: space, display: t(`gallery.space.${space}`) }))}\n .value=${this.chosenSpace}\n @change=${(e: CustomEvent) => (e.detail ? this.chooseSpace(e.detail as Space) : ((e.target as any).value = this.chosenSpace))}\n ></ox-input-select-buttons>\n </div>\n <div>\n <h4>${t('gallery.field.taken-on')}</h4>\n <input type=\"date\" .value=${this.takenOn} @change=${(e: any) => this.changeDay(e.target.value)} />\n </div>\n </section>\n\n ${\n company\n ? html`<section>\n <h4>${t('gallery.field.event')}</h4>\n <div class=\"chips\">\n <button\n class=\"chip\"\n aria-pressed=${String(!this.chosenEvent)}\n @click=${() => (this.chosenEvent = null)}\n >\n ${t('gallery.text.no-event')}\n </button>\n ${chosen && !shown.includes(chosen) ? this.choiceChip(chosen) : nothing}\n ${shown.map(one => this.choiceChip(one))}\n ${\n this.choices.length > FIRST_CHOICES && !this.allChoices\n ? html`<button class=\"chip\" @click=${() => (this.allChoices = true)}>\n ${t('gallery.button.more-events', { count: this.choices.length - FIRST_CHOICES })}\n </button>`\n : nothing\n }\n </div>\n </section>`\n : html`<section>\n <h4>${t('gallery.field.shared')}</h4>\n <ox-input-select-buttons\n .options=${[\n { value: 'me', display: t('gallery.text.only-me') },\n { value: 'everyone', display: t('gallery.text.everyone') }\n ]}\n .value=${this.shared ? 'everyone' : 'me'}\n @change=${(e: CustomEvent) => (e.detail ? (this.shared = e.detail === 'everyone') : ((e.target as any).value = this.shared ? 'everyone' : 'me'))}\n ></ox-input-select-buttons>\n <div class=\"muted\">${t(this.shared ? 'gallery.text.shared-note' : 'gallery.text.only-me-note')}</div>\n </section>`\n }\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" ?disabled=${this.busy} @click=${() => this.close()}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || total < 1} @click=${() => this.save()}\n >${this.post ? t('gallery.button.save') : t('gallery.button.post-count', { count: total })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private choiceChip(one: EventChoice) {\n return html`<button\n class=\"chip\"\n aria-pressed=${String(this.chosenEvent === one.id)}\n @click=${() => (this.chosenEvent = one.id)}\n >\n ${one.near ? html`<md-icon class=\"near\">event_available</md-icon>` : nothing}${one.name}<span class=\"muted\"\n >· ${day(one.startAt)}</span\n >\n </button>`\n }\n\n async firstUpdated() {\n const post = this.post\n if (post) {\n this.kept = [...post.photos]\n this.caption = post.caption ?? ''\n this.tags = [...(post.tags ?? [])]\n this.chosenSpace = post.space\n this.shared = post.shared\n this.chosenEvent = post.event?.id ?? null\n this.takenOn = dateText(new Date(post.takenAt))\n } else {\n this.chosenSpace = this.eventId ? 'COMPANY' : this.space\n this.chosenEvent = this.eventId ?? null\n }\n await this.add(this.files ?? [])\n await this.loadChoices()\n }\n\n disconnectedCallback() {\n for (const one of this.added) URL.revokeObjectURL(one.url)\n clearTimeout(this.suggestTimer)\n super.disconnectedCallback()\n }\n\n private async take(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n const before = this.kept.length + this.added.length\n await this.add(picked)\n /* The first photo says the day - the events near it come first. */\n if (!before && !this.post) await this.loadChoices()\n }\n\n private async add(files: File[]) {\n const room = MAX_PHOTOS - this.kept.length - this.added.length\n const photos = files\n .filter(file => /^image\\//i.test(file.type) || /\\.(jpe?g|png|gif|webp|heic|heif)$/i.test(file.name))\n .slice(0, Math.max(0, room))\n if (photos.length < files.length)\n notify({ level: 'warn', message: t('gallery.text.photos-skipped', { count: files.length - photos.length }) })\n if (!photos.length) return\n const first = !this.kept.length && !this.added.length && !this.post\n this.added = [...this.added, ...photos.map(file => ({ file, url: URL.createObjectURL(file) }))]\n if (first) {\n const takenAt = await takenAtOf(photos[0])\n if (takenAt) this.takenOn = dateText(takenAt)\n }\n }\n\n private drop(one: Added) {\n URL.revokeObjectURL(one.url)\n this.added = this.added.filter(other => other !== one)\n }\n\n private takenAt(): string {\n const [y, m, d] = this.takenOn.split('-').map(Number)\n const now = new Date()\n /* A day chosen without its hour keeps the hour it was posted - today's photo is not dated midnight. */\n const at = y ? new Date(y, m - 1, d, now.getHours(), now.getMinutes()) : now\n return at.toISOString()\n }\n\n private async loadChoices() {\n try {\n /* Offered, not chosen: the events near that day come first, and one press puts the post on one. */\n this.choices = await galleryApi.eventChoices(this.takenAt())\n } catch {\n this.choices = []\n }\n }\n\n private async changeDay(value: string) {\n if (!value) return\n this.takenOn = value\n await this.loadChoices()\n }\n\n private chooseSpace(space: Space) {\n this.chosenSpace = space\n if (space === 'PERSONAL') this.chosenEvent = null\n }\n\n private typeTag(value: string) {\n if (/[,\\s]$/.test(value) && value.trim()) {\n this.addTag(value)\n return\n }\n this.tagText = value\n clearTimeout(this.suggestTimer)\n this.suggestTimer = setTimeout(() => (this.suggestFor = this.tagText), 200)\n }\n\n private tagKey(e: KeyboardEvent) {\n if (e.isComposing) return\n if (e.key === 'Enter') {\n e.preventDefault()\n this.addTag(this.tagText)\n } else if (e.key === 'Backspace' && !this.tagText && this.tags.length) {\n this.tags = this.tags.slice(0, -1)\n }\n }\n\n /** Takes the typed tag, or says why not and keeps it - a longer tag was cut at 30 without a word (2026-10-30). */\n private addTag(raw: string): boolean {\n const tag = raw.replace(/[,]/g, ' ').trim().replace(/^#+/, '').replace(/\\s+/g, ' ').trim()\n if (tag.length > MAX_TAG) {\n this.tagRefusal = t('gallery.text.tag-too-long-typed', { max: MAX_TAG, length: tag.length })\n return false\n }\n this.tagRefusal = ''\n this.tagText = ''\n if (!tag || this.tags.length >= MAX_TAGS || this.tags.some(one => one.toLowerCase() === tag.toLowerCase())) return true\n this.tags = [...this.tags, tag]\n return true\n }\n\n private async save() {\n if (!this.addTag(this.tagText)) return\n this.busy = true\n try {\n const files = await Promise.all(this.added.map(one => shrunk(one.file)))\n const input = {\n space: this.chosenSpace,\n shared: this.chosenSpace === 'PERSONAL' && this.shared,\n caption: this.caption.trim(),\n takenAt: this.takenAt(),\n tags: this.tags,\n eventId: this.chosenSpace === 'COMPANY' ? this.chosenEvent : null\n }\n const uploading = (fraction: number) => (this.progress = fraction)\n const post = this.post\n ? await galleryApi.update(\n this.post.id,\n input,\n files,\n this.post.photos.filter(one => !this.kept.includes(one)).map(one => one.id),\n uploading\n )\n : await galleryApi.create(input, files, uploading)\n notify({ message: this.post ? t('gallery.text.saved') : t('gallery.text.posted') })\n galleryChanged()\n this.dispatchEvent(new CustomEvent('gallery-posted', { detail: post, bubbles: true, composed: true }))\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.progress = undefined\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -9,11 +9,14 @@ export declare class GalleryViewer extends GalleryViewer_base {
|
|
|
9
9
|
static styles: import("lit").CSSResult[];
|
|
10
10
|
post: Post;
|
|
11
11
|
private index;
|
|
12
|
-
|
|
12
|
+
/** Who liked it is shown under the heart once asked. */
|
|
13
|
+
private showingLikers;
|
|
13
14
|
private hiding;
|
|
14
15
|
private reason;
|
|
15
16
|
private burst;
|
|
16
17
|
private busy;
|
|
18
|
+
private likersRead;
|
|
19
|
+
private get likers();
|
|
17
20
|
render(): typeof nothing | import("lit-html").TemplateResult<1>;
|
|
18
21
|
private replace;
|
|
19
22
|
/** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */
|
|
@@ -9,8 +9,10 @@ import '@material/web/button/filled-button.js';
|
|
|
9
9
|
import '@material/web/button/text-button.js';
|
|
10
10
|
import '@material/web/icon/icon.js';
|
|
11
11
|
import '@operato/popup/ox-popup-actions.js';
|
|
12
|
+
import gql from 'graphql-tag';
|
|
12
13
|
import { css, html, LitElement, nothing } from 'lit';
|
|
13
14
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
15
|
+
import { QueryController } from '@operato/graphql';
|
|
14
16
|
import { i18next, localize } from '@operato/i18n';
|
|
15
17
|
import { notify } from '@operato/layout';
|
|
16
18
|
import { OxPrompt } from '@operato/popup/ox-prompt.js';
|
|
@@ -21,10 +23,15 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
21
23
|
constructor() {
|
|
22
24
|
super(...arguments);
|
|
23
25
|
this.index = 0;
|
|
26
|
+
/** Who liked it is shown under the heart once asked. */
|
|
27
|
+
this.showingLikers = false;
|
|
24
28
|
this.hiding = false;
|
|
25
29
|
this.reason = '';
|
|
26
30
|
this.burst = 0;
|
|
27
31
|
this.busy = false;
|
|
32
|
+
this.likersRead = new QueryController(this, gql `query ($id: String!) { galleryLikers(id: $id) { id name } }`, {
|
|
33
|
+
variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)
|
|
34
|
+
});
|
|
28
35
|
}
|
|
29
36
|
static { this.styles = [
|
|
30
37
|
CommonPopupStyles,
|
|
@@ -195,6 +202,9 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
195
202
|
}
|
|
196
203
|
`
|
|
197
204
|
]; }
|
|
205
|
+
get likers() {
|
|
206
|
+
return this.likersRead.data?.galleryLikers;
|
|
207
|
+
}
|
|
198
208
|
render() {
|
|
199
209
|
const post = this.post;
|
|
200
210
|
if (!post)
|
|
@@ -308,8 +318,8 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
308
318
|
try {
|
|
309
319
|
const state = await galleryApi.like(post.id, like);
|
|
310
320
|
this.post = { ...post, likeCount: state.likeCount, liked: state.liked };
|
|
311
|
-
if (this.
|
|
312
|
-
this.
|
|
321
|
+
if (this.showingLikers)
|
|
322
|
+
this.likersRead.refetch();
|
|
313
323
|
this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }));
|
|
314
324
|
}
|
|
315
325
|
catch (error) {
|
|
@@ -319,17 +329,8 @@ let GalleryViewer = class GalleryViewer extends localize(i18next)(LitElement) {
|
|
|
319
329
|
this.busy = false;
|
|
320
330
|
}
|
|
321
331
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
this.likers = undefined;
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
this.likers = await galleryApi.likers(this.post.id);
|
|
329
|
-
}
|
|
330
|
-
catch (error) {
|
|
331
|
-
notify({ level: 'error', message: reasonOf(error) });
|
|
332
|
-
}
|
|
332
|
+
showLikers() {
|
|
333
|
+
this.showingLikers = !this.showingLikers;
|
|
333
334
|
}
|
|
334
335
|
edit() {
|
|
335
336
|
this.close({ edit: this.post });
|
|
@@ -404,8 +405,8 @@ __decorate([
|
|
|
404
405
|
], GalleryViewer.prototype, "index", void 0);
|
|
405
406
|
__decorate([
|
|
406
407
|
state(),
|
|
407
|
-
__metadata("design:type",
|
|
408
|
-
], GalleryViewer.prototype, "
|
|
408
|
+
__metadata("design:type", Object)
|
|
409
|
+
], GalleryViewer.prototype, "showingLikers", void 0);
|
|
409
410
|
__decorate([
|
|
410
411
|
state(),
|
|
411
412
|
__metadata("design:type", Object)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gallery-viewer.js","sourceRoot":"","sources":["../../client/components/gallery-viewer.ts"],"names":[],"mappings":"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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"]}
|
|
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,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,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;QAC1B,wDAAwD;QACvC,kBAAa,GAAG,KAAK,CAAA;QACrB,WAAM,GAAG,KAAK,CAAA;QACd,WAAM,GAAG,EAAE,CAAA;QACX,UAAK,GAAG,CAAC,CAAA;QACT,SAAI,GAAG,KAAK,CAAA;QAErB,eAAU,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAA,6DAA6D,EAAE;YAC/G,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;SACtF,CAAC,CAAA;IA4MJ,CAAC;aAlYQ,WAAM,GAAG;QACd,iBAAiB;QACjB,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoKF;KACF,AAxKY,CAwKZ;IAgBD,IAAY,MAAM;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5C,CAAC;IAED,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,aAAa;gBAAE,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAA;YACjD,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,UAAU;QAChB,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,aAAa,CAAA;IAC1C,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;;AAvN+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;2CAAY;AAE1B;IAAhB,KAAK,EAAE;;4CAAkB;AAET;IAAhB,KAAK,EAAE;;oDAA8B;AACrB;IAAhB,KAAK,EAAE;;6CAAuB;AACd;IAAhB,KAAK,EAAE;;6CAAoB;AACX;IAAhB,KAAK,EAAE;;4CAAkB;AACT;IAAhB,KAAK,EAAE;;2CAAqB;AAnLlB,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAmYzB","sourcesContent":["/*\n * One post seen large (ADR-0165 decisions 4-6): its photos one by one - and across the whole screen (decision 9) - the like (the heart, or a double press on the\n * photo), who posted it and when, its event and tags - each opens the gallery narrowed to it. Its owner changes or\n * deletes it here; a moderator hides it here, with the reason, or shows it again. Where to go next is the popup's result\n * - a popup closes by going back in the history, so a page opened before it is gone would be gone with it.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { galleryApi, galleryChanged, type Post } from '../utils/gallery-api.js'\nimport { day, days, reasonOf, t } from '../utils/gallery-words.js'\n\n@customElement('gallery-viewer')\nexport class GalleryViewer extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .stage {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n max-height: 62vh;\n background: var(--md-sys-color-surface-container-highest);\n border-radius: var(--border-radius, 4px);\n overflow: hidden;\n user-select: none;\n }\n .stage img {\n max-width: 100%;\n max-height: 62vh;\n object-fit: contain;\n display: block;\n }\n .stage .turn {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .previous {\n inset-inline-start: var(--spacing-small, 4px);\n }\n .stage .next {\n inset-inline-end: var(--spacing-small, 4px);\n }\n .stage .large {\n position: absolute;\n top: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-small, 4px);\n display: inline-flex;\n padding: 4px;\n border: 0;\n border-radius: 50%;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n cursor: pointer;\n }\n .stage .index {\n position: absolute;\n bottom: var(--spacing-small, 4px);\n inset-inline-end: var(--spacing-medium, 8px);\n padding: 0 6px;\n border-radius: 999px;\n background: rgb(0 0 0 / 45%);\n color: #fff;\n font-size: var(--ui-t-small, 12px);\n }\n .burst {\n position: absolute;\n --md-icon-size: 72px;\n color: #fff;\n opacity: 0.9;\n animation: burst 600ms ease-out forwards;\n pointer-events: none;\n }\n @keyframes burst {\n from {\n transform: scale(0.6);\n opacity: 0.9;\n }\n to {\n transform: scale(1.3);\n opacity: 0;\n }\n }\n .line {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .heart {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n cursor: pointer;\n }\n /* The app's icons are drawn filled; an empty heart says not liked yet. */\n .heart md-icon {\n --md-icon-size: 22px;\n font-variation-settings: 'FILL' 0;\n }\n .heart[aria-pressed='true'] md-icon {\n color: var(--md-sys-color-error);\n font-variation-settings: 'FILL' 1;\n }\n .link {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n cursor: pointer;\n }\n .link:hover {\n text-decoration: underline;\n }\n .link md-icon {\n --md-icon-size: 14px;\n }\n .caption {\n margin: 0;\n font-size: var(--ui-t-body, 14px);\n line-height: 1.6;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n color: var(--md-sys-color-on-surface);\n }\n .hidden {\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-error-container);\n color: var(--md-sys-color-on-error-container);\n font-size: var(--ui-t-small, 12px);\n }\n .likers {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 56px;\n font: inherit;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n .spacer {\n margin-inline-end: auto;\n }\n `\n ]\n\n @property({ attribute: false }) post!: Post\n\n @state() private index = 0\n /** Who liked it is shown under the heart once asked. */\n @state() private showingLikers = false\n @state() private hiding = false\n @state() private reason = ''\n @state() private burst = 0\n @state() private busy = false\n\n private likersRead = new QueryController(this, gql`query ($id: String!) { galleryLikers(id: $id) { id name } }`, {\n variables: () => (this.showingLikers && this.post ? { id: this.post.id } : undefined)\n })\n\n private get likers(): { id: string; name?: string }[] | undefined {\n return this.likersRead.data?.galleryLikers\n }\n\n render() {\n const post = this.post\n if (!post) return nothing\n const photo = post.photos[this.index]\n const many = post.photos.length > 1\n return html`<div class=\"body\">\n ${post.hiddenAt ? html`<div class=\"hidden\">${t('gallery.text.hidden-note')}${post.hiddenReason ? ` · ${post.hiddenReason}` : ''}</div>` : nothing}\n <div class=\"stage\" @dblclick=${() => this.like(true, true)}>\n ${photo ? html`<img src=${photo.fullpath} alt=${post.caption ?? ''} />` : nothing}\n ${photo ? html`<button class=\"large\" aria-label=${t('gallery.button.large')} title=${t('gallery.button.large')} @click=${() => this.close({ show: { postId: post.id, index: this.index } })}><md-icon>fullscreen</md-icon></button>` : nothing}\n ${this.burst ? html`<md-icon class=\"burst\" style=\"font-variation-settings:'FILL' 1\">favorite</md-icon>` : nothing}\n ${\n many\n ? html`${this.index > 0 ? html`<button class=\"turn previous\" aria-label=${t('gallery.button.previous')} @click=${() => (this.index -= 1)}><md-icon>chevron_left</md-icon></button>` : nothing}\n ${this.index < post.photos.length - 1 ? html`<button class=\"turn next\" aria-label=${t('gallery.button.next')} @click=${() => (this.index += 1)}><md-icon>chevron_right</md-icon></button>` : nothing}\n <span class=\"index\">${this.index + 1} / ${post.photos.length}</span>`\n : nothing\n }\n </div>\n\n <div class=\"line\">\n <button\n class=\"heart\"\n aria-pressed=${String(post.liked)}\n aria-label=${t('gallery.button.like')}\n ?disabled=${this.busy}\n @click=${() => this.like(!post.liked)}\n >\n <md-icon>favorite</md-icon>\n </button>\n <button class=\"link\" ?disabled=${!post.likeCount} @click=${() => this.showLikers()}>\n ${t('gallery.text.like-count', { count: post.likeCount })}\n </button>\n <span class=\"spacer\"></span>\n <button class=\"link\" @click=${() => this.go(`gallery-page?author=${post.creator?.id}`)}>\n ${post.creator?.name ?? ''}\n </button>\n <span>${day(post.takenAt)}</span>\n </div>\n ${this.likers ? html`<div class=\"likers\">${this.likers.map(one => one.name).join(', ')}</div>` : nothing}\n ${post.caption ? html`<p class=\"caption\">${post.caption}</p>` : nothing}\n\n <div class=\"line\">\n ${\n post.event\n ? html`<button class=\"link\" @click=${() => this.go(`gallery-page?event=${post.event!.id}`)}>\n <md-icon>event</md-icon>${post.event.name} · ${days(post.event.startAt, post.event.endAt)}\n </button>`\n : nothing\n }\n ${(post.tags ?? []).map(tag => html`<button class=\"link\" @click=${() => this.go(`gallery-page?tag=${encodeURIComponent(tag)}`)}>#${tag}</button>`)}\n ${post.space === 'PERSONAL' ? html`<span>${t('gallery.space.PERSONAL')}${post.shared ? '' : ` · ${t('gallery.text.only-me')}`}</span>` : nothing}\n </div>\n\n ${\n this.hiding\n ? html`<div>\n <textarea\n maxlength=\"200\"\n placeholder=${t('gallery.text.hide-reason')}\n .value=${this.reason}\n @input=${(e: any) => (this.reason = e.target.value)}\n ></textarea>\n </div>`\n : nothing\n }\n </div>\n <ox-popup-actions>\n ${\n post.editable\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.edit()}\n >${t('gallery.button.edit')}</md-text-button\n >\n <md-text-button ?disabled=${this.busy} @click=${() => this.deletePost()}\n >${t('gallery.button.delete')}</md-text-button\n >`\n : nothing\n }\n ${\n post.moderatable && !this.hiding\n ? post.hiddenAt\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.unhide()}\n >${t('gallery.button.unhide')}</md-text-button\n >`\n : html`<md-text-button ?disabled=${this.busy} @click=${() => (this.hiding = true)}\n >${t('gallery.button.hide')}</md-text-button\n >`\n : nothing\n }\n ${\n this.hiding\n ? html`<md-text-button slot=\"cancel\" @click=${() => (this.hiding = false)}\n >${t('gallery.button.cancel')}</md-text-button\n >\n <md-filled-button\n slot=\"confirm\"\n ?disabled=${this.busy || !this.reason.trim()}\n @click=${() => this.hide()}\n >${t('gallery.button.hide')}</md-filled-button\n >`\n : html`<md-filled-button slot=\"confirm\" @click=${() => this.close()}\n >${t('gallery.button.close')}</md-filled-button\n >`\n }\n </ox-popup-actions>`\n }\n\n private replace(post: Post) {\n this.post = post\n this.index = Math.min(this.index, Math.max(0, post.photos.length - 1))\n galleryChanged()\n }\n\n /** Likes it, or takes the like back. A double press on the photo only likes - it never takes one back. */\n private async like(like: boolean, fromPhoto = false) {\n const post = this.post\n if (fromPhoto) {\n this.burst++\n setTimeout(() => (this.burst = 0), 600)\n if (post.liked) return\n }\n this.busy = true\n try {\n const state = await galleryApi.like(post.id, like)\n this.post = { ...post, likeCount: state.likeCount, liked: state.liked }\n if (this.showingLikers) this.likersRead.refetch()\n this.dispatchEvent(new CustomEvent('gallery-liked', { detail: this.post, bubbles: true, composed: true }))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private showLikers() {\n this.showingLikers = !this.showingLikers\n }\n\n private edit() {\n this.close({ edit: this.post })\n }\n\n private async deletePost() {\n const sure = await OxPrompt.open({\n title: t('gallery.button.delete'),\n text: t('gallery.text.delete-confirm'),\n confirmButton: { text: t('gallery.button.delete') },\n cancelButton: { text: t('gallery.button.cancel') }\n })\n if (!sure) return\n this.busy = true\n try {\n await galleryApi.remove(this.post.id)\n notify({ message: t('gallery.text.deleted') })\n galleryChanged()\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async hide() {\n this.busy = true\n try {\n const own = this.post.editable\n this.replace(await galleryApi.hide(this.post.id, this.reason.trim()))\n this.hiding = false\n this.reason = ''\n /* Its owner is told - unless the one hiding it is its owner. */\n notify({ message: own ? t('gallery.text.hidden-own') : t('gallery.text.hidden-done') })\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private async unhide() {\n this.busy = true\n try {\n this.replace(await galleryApi.unhide(this.post.id))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private go(address: string) {\n this.close({ go: address })\n }\n\n /** The next step - a page to go to, the post to change, or the photo to see large - goes as the popup's result: the page takes it once the popup is gone. */\n private close(next?: { go?: string; edit?: Post; show?: { postId: string; index: number } }) {\n this.dispatchEvent(new CustomEvent('done', { detail: next, bubbles: true, composed: true }))\n }\n}\n"]}
|