@things-factory/gallery 0.0.0-stage → 10.1.223
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 +16 -0
- package/client/components/gallery-forms.ts +188 -0
- package/client/components/gallery-uploader.ts +557 -0
- package/client/components/gallery-viewer.ts +397 -0
- package/client/index.ts +1 -0
- package/client/pages/gallery-page.ts +567 -0
- package/client/route.ts +8 -0
- package/client/tsconfig.json +13 -0
- package/client/utils/gallery-api.ts +157 -0
- package/client/utils/gallery-badge.ts +44 -0
- package/client/utils/gallery-words.ts +22 -0
- package/client/utils/photo-prep.ts +93 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +16 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/gallery-forms.d.ts +31 -0
- package/dist-client/components/gallery-forms.js +223 -0
- package/dist-client/components/gallery-forms.js.map +1 -0
- package/dist-client/components/gallery-uploader.d.ts +51 -0
- package/dist-client/components/gallery-uploader.js +588 -0
- package/dist-client/components/gallery-uploader.js.map +1 -0
- package/dist-client/components/gallery-viewer.d.ts +30 -0
- package/dist-client/components/gallery-viewer.js +416 -0
- package/dist-client/components/gallery-viewer.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/gallery-page.d.ts +55 -0
- package/dist-client/pages/gallery-page.js +586 -0
- package/dist-client/pages/gallery-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +9 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/utils/gallery-api.d.ts +95 -0
- package/dist-client/utils/gallery-api.js +46 -0
- package/dist-client/utils/gallery-api.js.map +1 -0
- package/dist-client/utils/gallery-badge.d.ts +4 -0
- package/dist-client/utils/gallery-badge.js +45 -0
- package/dist-client/utils/gallery-badge.js.map +1 -0
- package/dist-client/utils/gallery-words.d.ts +7 -0
- package/dist-client/utils/gallery-words.js +20 -0
- package/dist-client/utils/gallery-words.js.map +1 -0
- package/dist-client/utils/photo-prep.d.ts +10 -0
- package/dist-client/utils/photo-prep.js +102 -0
- package/dist-client/utils/photo-prep.js.map +1 -0
- package/dist-server/attachment-reader.d.ts +1 -0
- package/dist-server/attachment-reader.js +13 -0
- package/dist-server/attachment-reader.js.map +1 -0
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +11 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +15 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/gallery/gallery-resolver.d.ts +29 -0
- package/dist-server/service/gallery/gallery-resolver.js +602 -0
- package/dist-server/service/gallery/gallery-resolver.js.map +1 -0
- package/dist-server/service/gallery/gallery-rules.d.ts +88 -0
- package/dist-server/service/gallery/gallery-rules.js +181 -0
- package/dist-server/service/gallery/gallery-rules.js.map +1 -0
- package/dist-server/service/gallery/gallery-service.d.ts +37 -0
- package/dist-server/service/gallery/gallery-service.js +234 -0
- package/dist-server/service/gallery/gallery-service.js.map +1 -0
- package/dist-server/service/gallery/gallery-types.d.ts +62 -0
- package/dist-server/service/gallery/gallery-types.js +227 -0
- package/dist-server/service/gallery/gallery-types.js.map +1 -0
- package/dist-server/service/gallery/gallery.d.ts +83 -0
- package/dist-server/service/gallery/gallery.js +330 -0
- package/dist-server/service/gallery/gallery.js.map +1 -0
- package/dist-server/service/gallery/index.d.ts +4 -0
- package/dist-server/service/gallery/index.js +8 -0
- package/dist-server/service/gallery/index.js.map +1 -0
- package/dist-server/service/index.d.ts +7 -0
- package/dist-server/service/index.js +23 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +48 -4
- package/server/attachment-reader.ts +14 -0
- package/server/index.ts +9 -0
- package/server/role-tasks.ts +14 -0
- package/server/service/gallery/gallery-resolver.ts +541 -0
- package/server/service/gallery/gallery-rules.ts +187 -0
- package/server/service/gallery/gallery-service.ts +254 -0
- package/server/service/gallery/gallery-types.ts +151 -0
- package/server/service/gallery/gallery.ts +266 -0
- package/server/service/gallery/index.ts +5 -0
- package/server/service/index.ts +19 -0
- package/server/tsconfig.json +11 -0
- package/test/gallery-persistence.test.ts +372 -0
- package/test/gallery-rules.test.ts +140 -0
- package/test/open-doors.test.ts +62 -0
- package/test/photo-prep.test.ts +61 -0
- package/test/translations.test.ts +68 -0
- package/things-factory.config.js +8 -0
- package/translations/en.json +91 -0
- package/translations/es.json +91 -0
- package/translations/ja.json +91 -0
- package/translations/ko.json +91 -0
- package/translations/ms.json +91 -0
- package/translations/zh.json +91 -0
- package/README.md +0 -3
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { navigate, store } from '@operato/shell'
|
|
2
|
+
import { ADD_USER_MENU } from '@things-factory/apptool-base/client'
|
|
3
|
+
|
|
4
|
+
/* One's own gallery is in the menu the header's avatar opens, right after the profile (ADR-0165 decision 6). */
|
|
5
|
+
export default function bootstrap() {
|
|
6
|
+
store.dispatch({
|
|
7
|
+
type: ADD_USER_MENU,
|
|
8
|
+
item: {
|
|
9
|
+
name: 'my-gallery',
|
|
10
|
+
icon: 'photo_library',
|
|
11
|
+
label: 'gallery.title.my-gallery',
|
|
12
|
+
order: 12,
|
|
13
|
+
action: () => navigate('gallery-page?tab=mine')
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The two small forms of the gallery's moderators (ADR-0165 decision 5): an event made from the gallery, for one nobody
|
|
3
|
+
* put on the calendar yet, and a tag renamed on every post - into one already there, the two become one.
|
|
4
|
+
*/
|
|
5
|
+
import '@material/web/button/filled-button.js'
|
|
6
|
+
import '@material/web/button/text-button.js'
|
|
7
|
+
import '@operato/popup/ox-popup-actions.js'
|
|
8
|
+
|
|
9
|
+
import { css, html, LitElement } from 'lit'
|
|
10
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
11
|
+
|
|
12
|
+
import { i18next, localize } from '@operato/i18n'
|
|
13
|
+
import { notify } from '@operato/layout'
|
|
14
|
+
import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'
|
|
15
|
+
|
|
16
|
+
import { galleryApi, galleryChanged } from '../utils/gallery-api.js'
|
|
17
|
+
import { reasonOf, t } from '../utils/gallery-words.js'
|
|
18
|
+
|
|
19
|
+
const FormStyles = css`
|
|
20
|
+
:host {
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
.body {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: var(--spacing-medium, 8px);
|
|
27
|
+
}
|
|
28
|
+
label {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
gap: 2px;
|
|
32
|
+
font-size: var(--ui-t-small, 12px);
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
|
|
35
|
+
}
|
|
36
|
+
input {
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
font: inherit;
|
|
39
|
+
font-size: var(--ui-t-body, 14px);
|
|
40
|
+
font-weight: normal;
|
|
41
|
+
padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);
|
|
42
|
+
border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));
|
|
43
|
+
border-radius: var(--border-radius, 4px);
|
|
44
|
+
background: var(--md-sys-color-surface);
|
|
45
|
+
color: var(--md-sys-color-on-surface);
|
|
46
|
+
}
|
|
47
|
+
.row {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-wrap: wrap;
|
|
50
|
+
gap: var(--spacing-medium, 8px);
|
|
51
|
+
}
|
|
52
|
+
.note {
|
|
53
|
+
font-size: var(--ui-t-small, 12px);
|
|
54
|
+
color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
|
|
55
|
+
}
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
const local = (value: Date) => {
|
|
59
|
+
const pad = (n: number) => String(n).padStart(2, '0')
|
|
60
|
+
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@customElement('gallery-event-form')
|
|
64
|
+
export class GalleryEventForm extends localize(i18next)(LitElement) {
|
|
65
|
+
static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]
|
|
66
|
+
|
|
67
|
+
@state() private name = ''
|
|
68
|
+
@state() private startAt = local(new Date(new Date().setHours(9, 0, 0, 0)))
|
|
69
|
+
@state() private endAt = local(new Date(new Date().setHours(18, 0, 0, 0)))
|
|
70
|
+
@state() private location = ''
|
|
71
|
+
@state() private busy = false
|
|
72
|
+
|
|
73
|
+
render() {
|
|
74
|
+
const ready = this.name.trim() && this.startAt && this.endAt && this.endAt > this.startAt
|
|
75
|
+
return html`<div class="body">
|
|
76
|
+
<label
|
|
77
|
+
>${t('gallery.field.event-name')}<input
|
|
78
|
+
.value=${this.name}
|
|
79
|
+
@input=${(e: any) => (this.name = e.target.value)}
|
|
80
|
+
/></label>
|
|
81
|
+
<div class="row">
|
|
82
|
+
<label
|
|
83
|
+
>${t('gallery.field.starts')}<input
|
|
84
|
+
type="datetime-local"
|
|
85
|
+
.value=${this.startAt}
|
|
86
|
+
@change=${(e: any) => this.start(e.target.value)}
|
|
87
|
+
/></label>
|
|
88
|
+
<label
|
|
89
|
+
>${t('gallery.field.ends')}<input
|
|
90
|
+
type="datetime-local"
|
|
91
|
+
.value=${this.endAt}
|
|
92
|
+
@change=${(e: any) => (this.endAt = e.target.value)}
|
|
93
|
+
/></label>
|
|
94
|
+
</div>
|
|
95
|
+
<label
|
|
96
|
+
>${t('gallery.field.location')}<input
|
|
97
|
+
.value=${this.location}
|
|
98
|
+
@input=${(e: any) => (this.location = e.target.value)}
|
|
99
|
+
/></label>
|
|
100
|
+
<div class="note">${t('gallery.text.event-form-note')}</div>
|
|
101
|
+
</div>
|
|
102
|
+
<ox-popup-actions>
|
|
103
|
+
<md-text-button slot="cancel" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>
|
|
104
|
+
<md-filled-button slot="confirm" ?disabled=${this.busy || !ready} @click=${() => this.save()}
|
|
105
|
+
>${t('gallery.button.create-event')}</md-filled-button
|
|
106
|
+
>
|
|
107
|
+
</ox-popup-actions>`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** A later start carries the end with it, the same length. */
|
|
111
|
+
private start(value: string) {
|
|
112
|
+
const length = new Date(this.endAt).getTime() - new Date(this.startAt).getTime()
|
|
113
|
+
this.startAt = value
|
|
114
|
+
if (value && length > 0) this.endAt = local(new Date(new Date(value).getTime() + length))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private async save() {
|
|
118
|
+
this.busy = true
|
|
119
|
+
try {
|
|
120
|
+
const event = await galleryApi.createEvent({
|
|
121
|
+
name: this.name.trim(),
|
|
122
|
+
startAt: new Date(this.startAt).toISOString(),
|
|
123
|
+
endAt: new Date(this.endAt).toISOString(),
|
|
124
|
+
location: this.location.trim() || undefined
|
|
125
|
+
})
|
|
126
|
+
galleryChanged()
|
|
127
|
+
this.close(event)
|
|
128
|
+
} catch (error) {
|
|
129
|
+
notify({ level: 'error', message: reasonOf(error) })
|
|
130
|
+
} finally {
|
|
131
|
+
this.busy = false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** What was made goes as the popup's result. */
|
|
136
|
+
private close(result?: unknown) {
|
|
137
|
+
this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@customElement('gallery-tag-form')
|
|
142
|
+
export class GalleryTagForm extends localize(i18next)(LitElement) {
|
|
143
|
+
static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]
|
|
144
|
+
|
|
145
|
+
@property() tag = ''
|
|
146
|
+
@state() private to = ''
|
|
147
|
+
@state() private busy = false
|
|
148
|
+
|
|
149
|
+
render() {
|
|
150
|
+
const ready = this.to.trim().replace(/^#+/, '') && this.to.trim().replace(/^#+/, '') !== this.tag
|
|
151
|
+
return html`<div class="body">
|
|
152
|
+
<label
|
|
153
|
+
>${t('gallery.field.new-tag')}<input
|
|
154
|
+
.value=${this.to}
|
|
155
|
+
placeholder=${this.tag}
|
|
156
|
+
maxlength="31"
|
|
157
|
+
@input=${(e: any) => (this.to = e.target.value)}
|
|
158
|
+
/></label>
|
|
159
|
+
<div class="note">${t('gallery.text.tag-form-note', { tag: this.tag })}</div>
|
|
160
|
+
</div>
|
|
161
|
+
<ox-popup-actions>
|
|
162
|
+
<md-text-button slot="cancel" @click=${() => this.close()}>${t('gallery.button.cancel')}</md-text-button>
|
|
163
|
+
<md-filled-button slot="confirm" ?disabled=${this.busy || !ready} @click=${() => this.save()}
|
|
164
|
+
>${t('gallery.button.rename-tag')}</md-filled-button
|
|
165
|
+
>
|
|
166
|
+
</ox-popup-actions>`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private async save() {
|
|
170
|
+
this.busy = true
|
|
171
|
+
try {
|
|
172
|
+
const to = this.to.trim().replace(/^#+/, '')
|
|
173
|
+
const count = await galleryApi.renameTag(this.tag, to)
|
|
174
|
+
notify({ message: t('gallery.text.tag-renamed', { count }) })
|
|
175
|
+
galleryChanged()
|
|
176
|
+
this.close(to)
|
|
177
|
+
} catch (error) {
|
|
178
|
+
notify({ level: 'error', message: reasonOf(error) })
|
|
179
|
+
} finally {
|
|
180
|
+
this.busy = false
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** What was made goes as the popup's result. */
|
|
185
|
+
private close(result?: unknown) {
|
|
186
|
+
this.dispatchEvent(new CustomEvent('done', { detail: result, bubbles: true, composed: true }))
|
|
187
|
+
}
|
|
188
|
+
}
|