@things-factory/gallery 10.1.233 → 10.1.236
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/bootstrap.ts +12 -0
- package/client/components/gallery-forms.ts +1 -1
- package/client/components/gallery-saver-setting-let.ts +78 -0
- package/client/components/gallery-show.ts +312 -0
- package/client/components/gallery-uploader.ts +35 -5
- package/client/components/gallery-viewer.ts +17 -4
- package/client/pages/gallery-page.ts +18 -16
- package/client/utils/gallery-api.ts +4 -2
- package/client/utils/gallery-saver.ts +72 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +10 -0
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/gallery-forms.js +1 -1
- package/dist-client/components/gallery-forms.js.map +1 -1
- 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 +5 -0
- package/dist-client/components/gallery-uploader.js +43 -4
- package/dist-client/components/gallery-uploader.js.map +1 -1
- package/dist-client/components/gallery-viewer.d.ts +2 -2
- package/dist-client/components/gallery-viewer.js +16 -3
- package/dist-client/components/gallery-viewer.js.map +1 -1
- package/dist-client/pages/gallery-page.d.ts +0 -1
- package/dist-client/pages/gallery-page.js +20 -16
- package/dist-client/pages/gallery-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/gallery-api.d.ts +4 -0
- package/dist-client/utils/gallery-api.js +1 -1
- package/dist-client/utils/gallery-api.js.map +1 -1
- 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-server/service/gallery/gallery-resolver.js +13 -2
- package/dist-server/service/gallery/gallery-resolver.js.map +1 -1
- package/dist-server/service/gallery/gallery-rules.d.ts +4 -2
- package/dist-server/service/gallery/gallery-rules.js +4 -3
- package/dist-server/service/gallery/gallery-rules.js.map +1 -1
- package/dist-server/service/gallery/gallery-types.d.ts +3 -0
- package/dist-server/service/gallery/gallery-types.js +12 -0
- package/dist-server/service/gallery/gallery-types.js.map +1 -1
- package/dist-server/service/gallery/gallery.d.ts +2 -1
- package/dist-server/service/gallery/gallery.js +7 -2
- package/dist-server/service/gallery/gallery.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -9
- package/server/service/gallery/gallery-resolver.ts +13 -4
- package/server/service/gallery/gallery-rules.ts +5 -4
- package/server/service/gallery/gallery-types.ts +9 -0
- package/server/service/gallery/gallery.ts +7 -2
- package/test/gallery-persistence.test.ts +24 -3
- package/test/gallery-rules.test.ts +10 -4
- package/test/refusals-and-bounds.test.ts +28 -0
- package/translations/en.json +16 -2
- package/translations/es.json +16 -2
- package/translations/ja.json +16 -2
- package/translations/ko.json +16 -2
- package/translations/ms.json +16 -2
- package/translations/zh.json +16 -2
|
@@ -14,6 +14,7 @@ export type EventChoice = EventFacts & { near: boolean }
|
|
|
14
14
|
export interface Post {
|
|
15
15
|
id: string
|
|
16
16
|
space: Space
|
|
17
|
+
shared: boolean
|
|
17
18
|
caption?: string | null
|
|
18
19
|
takenAt: string
|
|
19
20
|
tags?: string[] | null
|
|
@@ -31,15 +32,16 @@ export interface Post {
|
|
|
31
32
|
|
|
32
33
|
export interface PostInput {
|
|
33
34
|
space?: Space
|
|
35
|
+
shared?: boolean
|
|
34
36
|
caption?: string
|
|
35
37
|
takenAt?: string
|
|
36
38
|
tags?: string[]
|
|
37
39
|
eventId?: string | null
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
export type Filter = { space?: Space; eventId?: string; tag?: string; authorId?: string }
|
|
42
|
+
export type Filter = { space?: Space; eventId?: string; tag?: string; authorId?: string; mine?: boolean; everyone?: boolean }
|
|
41
43
|
|
|
42
|
-
const POST_FIELDS = `id space caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt
|
|
44
|
+
const POST_FIELDS = `id space shared caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt
|
|
43
45
|
creator { id name } event { id name startAt endAt location } photos { id name thumbnail fullpath mimetype }`
|
|
44
46
|
const EVENT_FIELDS = 'id name startAt endAt location'
|
|
45
47
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The gallery as the screen saver (ADR-0165 decision 9): after the minutes set on this device with no press, move or
|
|
3
|
+
* key, the gallery everyone sees - the company's and the shared own photos - plays over the window until the person
|
|
4
|
+
* comes back. Kept on the device (`clientSettingStore`),
|
|
5
|
+
* since it is the screen that is left - a meeting room's display, not the person - and off until it is turned on.
|
|
6
|
+
*/
|
|
7
|
+
import { clientSettingStore } from '@operato/shell'
|
|
8
|
+
import { auth } from '@things-factory/auth-base/dist-client'
|
|
9
|
+
|
|
10
|
+
import { GalleryShow } from '../components/gallery-show.js'
|
|
11
|
+
|
|
12
|
+
const KEY = 'gallery-saver'
|
|
13
|
+
/** The waits the setting offers, in minutes; 0 is off. */
|
|
14
|
+
export const SAVER_MINUTES = [0, 5, 10, 30]
|
|
15
|
+
/** What says the person is here. */
|
|
16
|
+
const PRESENCE = ['pointermove', 'pointerdown', 'keydown', 'wheel', 'touchstart']
|
|
17
|
+
|
|
18
|
+
export async function saverMinutes(): Promise<number> {
|
|
19
|
+
try {
|
|
20
|
+
const minutes = Number((await clientSettingStore.get(KEY))?.value?.minutes)
|
|
21
|
+
return SAVER_MINUTES.includes(minutes) ? minutes : 0
|
|
22
|
+
} catch {
|
|
23
|
+
return 0
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function setSaverMinutes(minutes: number) {
|
|
28
|
+
await clientSettingStore.put({ key: KEY, value: { minutes } })
|
|
29
|
+
window.dispatchEvent(new CustomEvent('gallery-saver-changed'))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let minutes = 0
|
|
33
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
34
|
+
let signedIn = false
|
|
35
|
+
let showing: GalleryShow | undefined
|
|
36
|
+
|
|
37
|
+
function wait() {
|
|
38
|
+
clearTimeout(timer)
|
|
39
|
+
if (!minutes || !signedIn || showing) return
|
|
40
|
+
timer = setTimeout(start, minutes * 60_000)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function start() {
|
|
44
|
+
/* A hidden tab is not looked at; it waits for the next quiet stretch after it is shown. */
|
|
45
|
+
if (document.visibilityState !== 'visible' || document.querySelector('gallery-show')) return wait()
|
|
46
|
+
/* What everyone sees - never the photos the device's person keeps to themselves. */
|
|
47
|
+
showing = GalleryShow.open({ filter: { everyone: true }, saver: true })
|
|
48
|
+
showing.addEventListener('closed', () => {
|
|
49
|
+
showing = undefined
|
|
50
|
+
wait()
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Watches for the quiet stretch, once per application. */
|
|
55
|
+
export function watchForSaver() {
|
|
56
|
+
const read = async () => {
|
|
57
|
+
minutes = await saverMinutes()
|
|
58
|
+
wait()
|
|
59
|
+
}
|
|
60
|
+
for (const name of PRESENCE) window.addEventListener(name, () => !showing && wait(), { passive: true, capture: true })
|
|
61
|
+
document.addEventListener('visibilitychange', () => document.visibilityState === 'visible' && wait())
|
|
62
|
+
window.addEventListener('gallery-saver-changed', read)
|
|
63
|
+
auth.on('profile', () => {
|
|
64
|
+
signedIn = true
|
|
65
|
+
read()
|
|
66
|
+
})
|
|
67
|
+
auth.on('signout', () => {
|
|
68
|
+
signedIn = false
|
|
69
|
+
clearTimeout(timer)
|
|
70
|
+
showing?.close()
|
|
71
|
+
})
|
|
72
|
+
}
|
package/dist-client/bootstrap.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
1
2
|
import { navigate, store } from '@operato/shell';
|
|
2
3
|
import { ADD_USER_MENU } from '@things-factory/apptool-base/client';
|
|
4
|
+
import { ADD_SETTING } from '@things-factory/setting-base/dist-client';
|
|
5
|
+
import './components/gallery-saver-setting-let.js';
|
|
6
|
+
import { watchForSaver } from './utils/gallery-saver.js';
|
|
3
7
|
/* One's own gallery is in the menu the header's avatar opens, right after the profile (ADR-0165 decision 6). */
|
|
4
8
|
export default function bootstrap() {
|
|
5
9
|
store.dispatch({
|
|
@@ -12,5 +16,11 @@ export default function bootstrap() {
|
|
|
12
16
|
action: () => navigate('gallery-page?tab=mine')
|
|
13
17
|
}
|
|
14
18
|
});
|
|
19
|
+
/* The screen saver is the device's, so it is set among one's own settings (ADR-0165 decision 9). */
|
|
20
|
+
store.dispatch({
|
|
21
|
+
type: ADD_SETTING,
|
|
22
|
+
setting: { seq: 30, template: html `<gallery-saver-setting-let></gallery-saver-setting-let>` }
|
|
23
|
+
});
|
|
24
|
+
watchForSaver();
|
|
15
25
|
}
|
|
16
26
|
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAE1B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAA;AAEtE,OAAO,2CAA2C,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAExD,gHAAgH;AAChH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE;YACJ,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,0BAA0B;YACjC,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;SAChD;KACF,CAAC,CAAA;IACF,oGAAoG;IACpG,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAA,yDAAyD,EAAE;KAC9F,CAAC,CAAA;IACF,aAAa,EAAE,CAAA;AACjB,CAAC","sourcesContent":["import { html } from 'lit'\n\nimport { navigate, store } from '@operato/shell'\nimport { ADD_USER_MENU } from '@things-factory/apptool-base/client'\nimport { ADD_SETTING } from '@things-factory/setting-base/dist-client'\n\nimport './components/gallery-saver-setting-let.js'\nimport { watchForSaver } from './utils/gallery-saver.js'\n\n/* One's own gallery is in the menu the header's avatar opens, right after the profile (ADR-0165 decision 6). */\nexport default function bootstrap() {\n store.dispatch({\n type: ADD_USER_MENU,\n item: {\n name: 'my-gallery',\n icon: 'photo_library',\n label: 'gallery.title.my-gallery',\n order: 12,\n action: () => navigate('gallery-page?tab=mine')\n }\n })\n /* The screen saver is the device's, so it is set among one's own settings (ADR-0165 decision 9). */\n store.dispatch({\n type: ADD_SETTING,\n setting: { seq: 30, template: html`<gallery-saver-setting-let></gallery-saver-setting-let>` }\n })\n watchForSaver()\n}\n"]}
|
|
@@ -171,7 +171,7 @@ let GalleryTagForm = class GalleryTagForm extends localize(i18next)(LitElement)
|
|
|
171
171
|
>${t('gallery.field.new-tag')}<input
|
|
172
172
|
.value=${this.to}
|
|
173
173
|
placeholder=${this.tag}
|
|
174
|
-
maxlength="
|
|
174
|
+
maxlength="30"
|
|
175
175
|
@input=${(e) => (this.to = e.target.value)}
|
|
176
176
|
/></label>
|
|
177
177
|
<div class="note">${t('gallery.text.tag-form-note', { tag: this.tag })}</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gallery-forms.js","sourceRoot":"","sources":["../../client/components/gallery-forms.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The two small forms of the gallery's moderators (ADR-0165 decision 5): an event made from the gallery, for one nobody\n * put on the calendar yet, and a tag renamed on every post - into one already there, the two become one.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { galleryApi, galleryChanged } from '../utils/gallery-api.js'\nimport { reasonOf, t } from '../utils/gallery-words.js'\n\nconst FormStyles = css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n label {\n display: flex;\n flex-direction: column;\n gap: 2px;\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 input {\n box-sizing: border-box;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n font-weight: normal;\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 .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-medium, 8px);\n }\n .note {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n`\n\nconst local = (value: Date) => {\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`\n}\n\n@customElement('gallery-event-form')\nexport class GalleryEventForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n\n @state() private name = ''\n @state() private startAt = local(new Date(new Date().setHours(9, 0, 0, 0)))\n @state() private endAt = local(new Date(new Date().setHours(18, 0, 0, 0)))\n @state() private location = ''\n @state() private busy = false\n\n render() {\n const ready = this.name.trim() && this.startAt && this.endAt && this.endAt > this.startAt\n return html`<div class=\"body\">\n <label\n >${t('gallery.field.event-name')}<input\n .value=${this.name}\n @input=${(e: any) => (this.name = e.target.value)}\n /></label>\n <div class=\"row\">\n <label\n >${t('gallery.field.starts')}<input\n type=\"datetime-local\"\n .value=${this.startAt}\n @change=${(e: any) => this.start(e.target.value)}\n /></label>\n <label\n >${t('gallery.field.ends')}<input\n type=\"datetime-local\"\n .value=${this.endAt}\n @change=${(e: any) => (this.endAt = e.target.value)}\n /></label>\n </div>\n <label\n >${t('gallery.field.location')}<input\n .value=${this.location}\n @input=${(e: any) => (this.location = e.target.value)}\n /></label>\n <div class=\"note\">${t('gallery.text.event-form-note')}</div>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !ready} @click=${() => this.save()}\n >${t('gallery.button.create-event')}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n /** A later start carries the end with it, the same length. */\n private start(value: string) {\n const length = new Date(this.endAt).getTime() - new Date(this.startAt).getTime()\n this.startAt = value\n if (value && length > 0) this.endAt = local(new Date(new Date(value).getTime() + length))\n }\n\n private async save() {\n this.busy = true\n try {\n const event = await galleryApi.createEvent({\n name: this.name.trim(),\n startAt: new Date(this.startAt).toISOString(),\n endAt: new Date(this.endAt).toISOString(),\n location: this.location.trim() || undefined\n })\n galleryChanged()\n this.close(event)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n /** What was made goes as the popup's result. */\n private close(result?: unknown) {\n this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))\n }\n}\n\n@customElement('gallery-tag-form')\nexport class GalleryTagForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n\n @property() tag = ''\n @state() private to = ''\n @state() private busy = false\n\n render() {\n const ready = this.to.trim().replace(/^#+/, '') && this.to.trim().replace(/^#+/, '') !== this.tag\n return html`<div class=\"body\">\n <label\n >${t('gallery.field.new-tag')}<input\n .value=${this.to}\n placeholder=${this.tag}\n maxlength=\"31\"\n @input=${(e: any) => (this.to = e.target.value)}\n /></label>\n <div class=\"note\">${t('gallery.text.tag-form-note', { tag: this.tag })}</div>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !ready} @click=${() => this.save()}\n >${t('gallery.button.rename-tag')}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private async save() {\n this.busy = true\n try {\n const to = this.to.trim().replace(/^#+/, '')\n const count = await galleryApi.renameTag(this.tag, to)\n notify({ message: t('gallery.text.tag-renamed', { count }) })\n galleryChanged()\n this.close(to)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n /** What was made goes as the popup's result. */\n private close(result?: unknown) {\n this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"gallery-forms.js","sourceRoot":"","sources":["../../client/components/gallery-forms.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The two small forms of the gallery's moderators (ADR-0165 decision 5): an event made from the gallery, for one nobody\n * put on the calendar yet, and a tag renamed on every post - into one already there, the two become one.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { galleryApi, galleryChanged } from '../utils/gallery-api.js'\nimport { reasonOf, t } from '../utils/gallery-words.js'\n\nconst FormStyles = css`\n :host {\n height: 100%;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n label {\n display: flex;\n flex-direction: column;\n gap: 2px;\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 input {\n box-sizing: border-box;\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n font-weight: normal;\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 .row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-medium, 8px);\n }\n .note {\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n`\n\nconst local = (value: Date) => {\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`\n}\n\n@customElement('gallery-event-form')\nexport class GalleryEventForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n\n @state() private name = ''\n @state() private startAt = local(new Date(new Date().setHours(9, 0, 0, 0)))\n @state() private endAt = local(new Date(new Date().setHours(18, 0, 0, 0)))\n @state() private location = ''\n @state() private busy = false\n\n render() {\n const ready = this.name.trim() && this.startAt && this.endAt && this.endAt > this.startAt\n return html`<div class=\"body\">\n <label\n >${t('gallery.field.event-name')}<input\n .value=${this.name}\n @input=${(e: any) => (this.name = e.target.value)}\n /></label>\n <div class=\"row\">\n <label\n >${t('gallery.field.starts')}<input\n type=\"datetime-local\"\n .value=${this.startAt}\n @change=${(e: any) => this.start(e.target.value)}\n /></label>\n <label\n >${t('gallery.field.ends')}<input\n type=\"datetime-local\"\n .value=${this.endAt}\n @change=${(e: any) => (this.endAt = e.target.value)}\n /></label>\n </div>\n <label\n >${t('gallery.field.location')}<input\n .value=${this.location}\n @input=${(e: any) => (this.location = e.target.value)}\n /></label>\n <div class=\"note\">${t('gallery.text.event-form-note')}</div>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !ready} @click=${() => this.save()}\n >${t('gallery.button.create-event')}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n /** A later start carries the end with it, the same length. */\n private start(value: string) {\n const length = new Date(this.endAt).getTime() - new Date(this.startAt).getTime()\n this.startAt = value\n if (value && length > 0) this.endAt = local(new Date(new Date(value).getTime() + length))\n }\n\n private async save() {\n this.busy = true\n try {\n const event = await galleryApi.createEvent({\n name: this.name.trim(),\n startAt: new Date(this.startAt).toISOString(),\n endAt: new Date(this.endAt).toISOString(),\n location: this.location.trim() || undefined\n })\n galleryChanged()\n this.close(event)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n /** What was made goes as the popup's result. */\n private close(result?: unknown) {\n this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))\n }\n}\n\n@customElement('gallery-tag-form')\nexport class GalleryTagForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n\n @property() tag = ''\n @state() private to = ''\n @state() private busy = false\n\n render() {\n const ready = this.to.trim().replace(/^#+/, '') && this.to.trim().replace(/^#+/, '') !== this.tag\n return html`<div class=\"body\">\n <label\n >${t('gallery.field.new-tag')}<input\n .value=${this.to}\n placeholder=${this.tag}\n maxlength=\"30\"\n @input=${(e: any) => (this.to = e.target.value)}\n /></label>\n <div class=\"note\">${t('gallery.text.tag-form-note', { tag: this.tag })}</div>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !ready} @click=${() => this.save()}\n >${t('gallery.button.rename-tag')}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private async save() {\n this.busy = true\n try {\n const to = this.to.trim().replace(/^#+/, '')\n const count = await galleryApi.renameTag(this.tag, to)\n notify({ message: t('gallery.text.tag-renamed', { count }) })\n galleryChanged()\n this.close(to)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n /** What was made goes as the popup's result. */\n private close(result?: unknown) {\n this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import '@material/web/radio/radio.js';
|
|
2
|
+
import { LitElement } from 'lit';
|
|
3
|
+
declare const GallerySaverSettingLet_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
4
|
+
export declare class GallerySaverSettingLet extends GallerySaverSettingLet_base {
|
|
5
|
+
static styles: import("lit").CSSResult;
|
|
6
|
+
private minutes;
|
|
7
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
8
|
+
firstUpdated(): Promise<void>;
|
|
9
|
+
private choose;
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
/*
|
|
3
|
+
* Settings › the gallery as the screen saver on this device (ADR-0165 decision 9): off, or after a few quiet minutes.
|
|
4
|
+
*/
|
|
5
|
+
import '@material/web/radio/radio.js';
|
|
6
|
+
import { css, html, LitElement } from 'lit';
|
|
7
|
+
import { customElement, state } from 'lit/decorators.js';
|
|
8
|
+
import { i18next, localize } from '@operato/i18n';
|
|
9
|
+
import { notify } from '@operato/layout';
|
|
10
|
+
import { SAVER_MINUTES, saverMinutes, setSaverMinutes } from '../utils/gallery-saver.js';
|
|
11
|
+
import { reasonOf, t } from '../utils/gallery-words.js';
|
|
12
|
+
let GallerySaverSettingLet = class GallerySaverSettingLet extends localize(i18next)(LitElement) {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.minutes = 0;
|
|
16
|
+
}
|
|
17
|
+
static { this.styles = css `
|
|
18
|
+
div[slot='content'] {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: var(--spacing-medium, 8px);
|
|
22
|
+
}
|
|
23
|
+
.choices {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-wrap: wrap;
|
|
26
|
+
gap: var(--spacing-small, 4px) var(--spacing-large, 12px);
|
|
27
|
+
}
|
|
28
|
+
label {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: 6px;
|
|
31
|
+
align-items: center;
|
|
32
|
+
font: var(--label-font);
|
|
33
|
+
color: var(--md-sys-color-on-surface);
|
|
34
|
+
}
|
|
35
|
+
.note {
|
|
36
|
+
margin: 0;
|
|
37
|
+
font-size: var(--ui-t-small, 12px);
|
|
38
|
+
color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
|
|
39
|
+
}
|
|
40
|
+
`; }
|
|
41
|
+
render() {
|
|
42
|
+
return html `<setting-let>
|
|
43
|
+
<span slot="title">${t('gallery.title.saver')}</span>
|
|
44
|
+
<div slot="content">
|
|
45
|
+
<div class="choices" role="radiogroup">
|
|
46
|
+
${SAVER_MINUTES.map(minutes => html `<label>
|
|
47
|
+
<md-radio
|
|
48
|
+
name="gallery-saver"
|
|
49
|
+
value=${String(minutes)}
|
|
50
|
+
?checked=${this.minutes === minutes}
|
|
51
|
+
@change=${() => this.choose(minutes)}
|
|
52
|
+
></md-radio>
|
|
53
|
+
${minutes ? t('gallery.text.saver-after', { minutes }) : t('gallery.text.saver-off')}
|
|
54
|
+
</label>`)}
|
|
55
|
+
</div>
|
|
56
|
+
<p class="note">${t('gallery.text.saver-note')}</p>
|
|
57
|
+
</div>
|
|
58
|
+
</setting-let>`;
|
|
59
|
+
}
|
|
60
|
+
async firstUpdated() {
|
|
61
|
+
this.minutes = await saverMinutes();
|
|
62
|
+
}
|
|
63
|
+
async choose(minutes) {
|
|
64
|
+
try {
|
|
65
|
+
await setSaverMinutes(minutes);
|
|
66
|
+
this.minutes = minutes;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
notify({ level: 'error', message: reasonOf(error) });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
__decorate([
|
|
74
|
+
state(),
|
|
75
|
+
__metadata("design:type", Object)
|
|
76
|
+
], GallerySaverSettingLet.prototype, "minutes", void 0);
|
|
77
|
+
GallerySaverSettingLet = __decorate([
|
|
78
|
+
customElement('gallery-saver-setting-let')
|
|
79
|
+
], GallerySaverSettingLet);
|
|
80
|
+
export { GallerySaverSettingLet };
|
|
81
|
+
//# sourceMappingURL=gallery-saver-setting-let.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gallery-saver-setting-let.js","sourceRoot":"","sources":["../../client/components/gallery-saver-setting-let.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,8BAA8B,CAAA;AAErC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AACxF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAGhD,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAlE;;QA0BY,YAAO,GAAG,CAAC,CAAA;IAoC9B,CAAC;aA7DQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBlB,AAvBY,CAuBZ;IAID,MAAM;QACJ,OAAO,IAAI,CAAA;2BACY,CAAC,CAAC,qBAAqB,CAAC;;;YAGvC,aAAa,CAAC,GAAG,CACjB,OAAO,CAAC,EAAE,CAAC,IAAI,CAAA;;;wBAGH,MAAM,CAAC,OAAO,CAAC;2BACZ,IAAI,CAAC,OAAO,KAAK,OAAO;0BACzB,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;gBAEpC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC;qBAC7E,CACV;;0BAEe,CAAC,CAAC,yBAAyB,CAAC;;mBAEnC,CAAA;IACjB,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,OAAO,GAAG,MAAM,YAAY,EAAE,CAAA;IACrC,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,OAAe;QAClC,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,OAAO,CAAC,CAAA;YAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACxB,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;;AAnCgB;IAAhB,KAAK,EAAE;;uDAAoB;AA1BjB,sBAAsB;IADlC,aAAa,CAAC,2BAA2B,CAAC;GAC9B,sBAAsB,CA8DlC","sourcesContent":["/*\n * Settings › the gallery as the screen saver on this device (ADR-0165 decision 9): off, or after a few quiet minutes.\n */\nimport '@material/web/radio/radio.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\n\nimport { SAVER_MINUTES, saverMinutes, setSaverMinutes } from '../utils/gallery-saver.js'\nimport { reasonOf, t } from '../utils/gallery-words.js'\n\n@customElement('gallery-saver-setting-let')\nexport class GallerySaverSettingLet extends localize(i18next)(LitElement) {\n static styles = css`\n div[slot='content'] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .choices {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px) var(--spacing-large, 12px);\n }\n label {\n display: flex;\n gap: 6px;\n align-items: center;\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n }\n .note {\n margin: 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n `\n\n @state() private minutes = 0\n\n render() {\n return html`<setting-let>\n <span slot=\"title\">${t('gallery.title.saver')}</span>\n <div slot=\"content\">\n <div class=\"choices\" role=\"radiogroup\">\n ${SAVER_MINUTES.map(\n minutes => html`<label>\n <md-radio\n name=\"gallery-saver\"\n value=${String(minutes)}\n ?checked=${this.minutes === minutes}\n @change=${() => this.choose(minutes)}\n ></md-radio>\n ${minutes ? t('gallery.text.saver-after', { minutes }) : t('gallery.text.saver-off')}\n </label>`\n )}\n </div>\n <p class=\"note\">${t('gallery.text.saver-note')}</p>\n </div>\n </setting-let>`\n }\n\n async firstUpdated() {\n this.minutes = await saverMinutes()\n }\n\n private async choose(minutes: number) {\n try {\n await setSaverMinutes(minutes)\n this.minutes = minutes\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import '@material/web/icon/icon.js';
|
|
2
|
+
import { LitElement, nothing } from 'lit';
|
|
3
|
+
import { type Filter } from '../utils/gallery-api.js';
|
|
4
|
+
export type ShowOptions = {
|
|
5
|
+
/** The posts the show walks through - the gallery's narrowing where it was opened. */
|
|
6
|
+
filter: Filter;
|
|
7
|
+
/** Where it starts: a post and the photo in it. Without it, the first photo. */
|
|
8
|
+
start?: {
|
|
9
|
+
postId: string;
|
|
10
|
+
index: number;
|
|
11
|
+
};
|
|
12
|
+
/** Plays at once. */
|
|
13
|
+
playing?: boolean;
|
|
14
|
+
/** The screen saver: plays in a random order, and closes at anything the person does. */
|
|
15
|
+
saver?: boolean;
|
|
16
|
+
};
|
|
17
|
+
declare const GalleryShow_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
18
|
+
export declare class GalleryShow extends GalleryShow_base {
|
|
19
|
+
static styles: import("lit").CSSResult;
|
|
20
|
+
/** Opens a show over the whole window, and the whole screen when the browser lets it. */
|
|
21
|
+
static open(options: ShowOptions): GalleryShow;
|
|
22
|
+
saver: boolean;
|
|
23
|
+
options: ShowOptions;
|
|
24
|
+
private frames;
|
|
25
|
+
private at;
|
|
26
|
+
private playing;
|
|
27
|
+
private loaded;
|
|
28
|
+
private timer?;
|
|
29
|
+
private wholeScreen;
|
|
30
|
+
private disposed;
|
|
31
|
+
render(): typeof nothing | import("lit-html").TemplateResult<1>;
|
|
32
|
+
private renderBar;
|
|
33
|
+
connectedCallback(): void;
|
|
34
|
+
disconnectedCallback(): void;
|
|
35
|
+
private load;
|
|
36
|
+
private play;
|
|
37
|
+
/** The next photo after the dwell, asked ahead so it is there when it turns. */
|
|
38
|
+
private schedule;
|
|
39
|
+
private step;
|
|
40
|
+
private onKey;
|
|
41
|
+
/** Leaving the whole screen (Esc there is the browser's) leaves the show too. */
|
|
42
|
+
private onFullscreen;
|
|
43
|
+
private onWake;
|
|
44
|
+
close(): void;
|
|
45
|
+
}
|
|
46
|
+
export {};
|