@bendyline/gilde 0.1.21 → 0.1.22
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/authoring/chat-models/nemotron3.5-lightning-30b-q4.json +3 -2
- package/authoring/chat-models/nemotron3.5-lightning-30b-q8.json +3 -2
- package/authoring/page-demo-stub.js +85 -0
- package/data/chat-models/index.json +1 -1
- package/data/chat-models/ne/nemotron3.5-lightning-30b-q4/manifest.json +3 -2
- package/data/chat-models/ne/nemotron3.5-lightning-30b-q8/manifest.json +3 -2
- package/data/connector-types/bl/bluesky-posts/manifest.json +16 -0
- package/data/connector-types/bl/bluesky-posts/versions/1.0.0/manifest.json +70 -0
- package/data/connector-types/gi/github-issues/versions/1.0.1/manifest.json +67 -0
- package/data/connector-types/in/instagram-media/manifest.json +17 -0
- package/data/connector-types/in/instagram-media/versions/1.0.0/manifest.json +70 -0
- package/data/connector-types/index.json +1 -1
- package/data/connector-types/x-/x-posts/manifest.json +17 -0
- package/data/connector-types/x-/x-posts/versions/1.0.0/manifest.json +66 -0
- package/data/craftbook-templates/dr/draft-social-post/manifest.json +23 -0
- package/data/craftbook-templates/dr/draft-social-post/versions/1.0.0/craftbook.json +176 -0
- package/data/craftbook-templates/dr/draft-social-post/versions/1.0.0/test.json +161 -0
- package/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/re/reception-report/manifest.json +21 -0
- package/data/craftbook-templates/re/reception-report/versions/1.0.0/craftbook.json +170 -0
- package/data/craftbook-templates/re/reception-report/versions/1.0.0/test.json +168 -0
- package/data/craftbook-templates/so/social-digest/manifest.json +21 -0
- package/data/craftbook-templates/so/social-digest/versions/1.0.0/craftbook.json +133 -0
- package/data/craftbook-templates/so/social-digest/versions/1.0.0/test.json +168 -0
- package/data/gezel-templates/index.json +1 -1
- package/data/gezel-templates/om/omroeper/manifest.json +20 -0
- package/data/gezel-templates/om/omroeper/versions/1.0.0/about.md +33 -0
- package/data/gezel-templates/om/omroeper/versions/1.0.0/manifest.json +23 -0
- package/data/project-types/im/image-feed/manifest.json +20 -0
- package/data/project-types/im/image-feed/versions/1.0.0/about.md +21 -0
- package/data/project-types/im/image-feed/versions/1.0.0/manifest.json +330 -0
- package/data/project-types/im/image-feed/versions/1.0.0/mission.md +10 -0
- package/data/project-types/im/image-feed/versions/1.0.0/pages/gallery/index.html +831 -0
- package/data/project-types/im/image-feed/versions/1.0.0/posts/index.json +4 -0
- package/data/project-types/im/image-feed/versions/1.0.0/style-guide.md +24 -0
- package/data/project-types/index.json +1 -1
- package/data/project-types/so/social-feed/manifest.json +20 -0
- package/data/project-types/so/social-feed/versions/1.0.0/about.md +19 -0
- package/data/project-types/so/social-feed/versions/1.0.0/manifest.json +330 -0
- package/data/project-types/so/social-feed/versions/1.0.0/mission.md +10 -0
- package/data/project-types/so/social-feed/versions/1.0.0/pages/dashboard/index.html +754 -0
- package/data/project-types/so/social-feed/versions/1.0.0/posts/index.json +4 -0
- package/data/project-types/so/social-feed/versions/1.0.0/voice-guide.md +22 -0
- package/package.json +1 -1
- package/schemas/connector-type-version.schema.json +6 -0
- package/schemas/craftbook-test.schema.json +1 -0
- package/schemas/project-type-version.schema.json +4 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="gezel-demo" content="standalone" />
|
|
7
|
+
<title>Image feed gallery</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light dark;
|
|
11
|
+
--bg: #faf7f2;
|
|
12
|
+
--card: #fff;
|
|
13
|
+
--ink: #2b2620;
|
|
14
|
+
--muted: #7a7166;
|
|
15
|
+
--accent: #b5651d;
|
|
16
|
+
--track: #ece5da;
|
|
17
|
+
--good: #4a7c59;
|
|
18
|
+
--warn: #a4552e;
|
|
19
|
+
}
|
|
20
|
+
:root[data-theme='dark'] {
|
|
21
|
+
--bg: #1c1a17;
|
|
22
|
+
--card: #262320;
|
|
23
|
+
--ink: #efe9e0;
|
|
24
|
+
--muted: #a59a8c;
|
|
25
|
+
--accent: #e0894a;
|
|
26
|
+
--track: #3a352f;
|
|
27
|
+
--good: #7fae8d;
|
|
28
|
+
--warn: #d98a63;
|
|
29
|
+
}
|
|
30
|
+
@media (prefers-color-scheme: dark) {
|
|
31
|
+
:root:not([data-theme='light']) {
|
|
32
|
+
--bg: #1c1a17;
|
|
33
|
+
--card: #262320;
|
|
34
|
+
--ink: #efe9e0;
|
|
35
|
+
--muted: #a59a8c;
|
|
36
|
+
--accent: #e0894a;
|
|
37
|
+
--track: #3a352f;
|
|
38
|
+
--good: #7fae8d;
|
|
39
|
+
--warn: #d98a63;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
* { box-sizing: border-box; }
|
|
43
|
+
body {
|
|
44
|
+
margin: 0;
|
|
45
|
+
font: 15px/1.5 system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
46
|
+
background: var(--bg);
|
|
47
|
+
color: var(--ink);
|
|
48
|
+
padding: 1.5rem 1.25rem 2rem;
|
|
49
|
+
}
|
|
50
|
+
main { max-width: 1080px; margin: 0 auto; }
|
|
51
|
+
h1 {
|
|
52
|
+
font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
|
|
53
|
+
font-size: 1.4rem;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
margin: 0 0 0.15rem;
|
|
56
|
+
overflow-wrap: anywhere;
|
|
57
|
+
}
|
|
58
|
+
.head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; }
|
|
59
|
+
.sub { color: var(--muted); margin: 0 0 1rem; font-size: 0.9rem; }
|
|
60
|
+
.hint { color: var(--muted); font-size: 0.8rem; margin: 0 0 0.9rem; }
|
|
61
|
+
.key {
|
|
62
|
+
font: inherit;
|
|
63
|
+
font-size: 0.8rem;
|
|
64
|
+
padding: 0.25rem 0.55rem;
|
|
65
|
+
border: 1px solid var(--track);
|
|
66
|
+
border-radius: 6px;
|
|
67
|
+
background: var(--card);
|
|
68
|
+
color: var(--ink);
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
}
|
|
71
|
+
.key:hover { border-color: var(--muted); }
|
|
72
|
+
.key[aria-pressed='true'] {
|
|
73
|
+
border-color: var(--accent);
|
|
74
|
+
color: var(--accent);
|
|
75
|
+
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
|
|
76
|
+
}
|
|
77
|
+
.note {
|
|
78
|
+
margin: 0 0 0.85rem;
|
|
79
|
+
padding: 0.5rem 0.65rem;
|
|
80
|
+
border: 1px solid var(--track);
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
background: var(--card);
|
|
83
|
+
color: var(--muted);
|
|
84
|
+
font-size: 0.8rem;
|
|
85
|
+
}
|
|
86
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 0.75rem; }
|
|
87
|
+
.shot {
|
|
88
|
+
display: block;
|
|
89
|
+
width: 100%;
|
|
90
|
+
padding: 0;
|
|
91
|
+
text-align: left;
|
|
92
|
+
font: inherit;
|
|
93
|
+
color: var(--ink);
|
|
94
|
+
background: var(--card);
|
|
95
|
+
border: 1px solid var(--track);
|
|
96
|
+
border-radius: 6px;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
position: relative;
|
|
100
|
+
}
|
|
101
|
+
.shot:hover { border-color: var(--muted); }
|
|
102
|
+
.shot .pic { display: block; position: relative; aspect-ratio: 1 / 1; background: var(--track); }
|
|
103
|
+
.shot .pic img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
104
|
+
.shot .pic .tcard {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
width: 100%;
|
|
109
|
+
height: 100%;
|
|
110
|
+
padding: 0.75rem;
|
|
111
|
+
background: color-mix(in srgb, var(--card) 78%, var(--accent));
|
|
112
|
+
color: var(--ink);
|
|
113
|
+
font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
|
|
114
|
+
font-size: 1.02rem;
|
|
115
|
+
text-align: center;
|
|
116
|
+
overflow-wrap: anywhere;
|
|
117
|
+
}
|
|
118
|
+
.shot .st {
|
|
119
|
+
position: absolute;
|
|
120
|
+
top: 0.4rem;
|
|
121
|
+
left: 0.4rem;
|
|
122
|
+
border: 1px solid var(--track);
|
|
123
|
+
border-radius: 4px;
|
|
124
|
+
padding: 0 0.3rem;
|
|
125
|
+
font-size: 0.7rem;
|
|
126
|
+
line-height: 1.5;
|
|
127
|
+
background: var(--card);
|
|
128
|
+
color: var(--muted);
|
|
129
|
+
}
|
|
130
|
+
.shot .st.st-draft, .shot .st.st-scheduled { color: var(--accent); border-color: var(--accent); }
|
|
131
|
+
.shot .st.st-in-review { color: var(--warn); border-color: var(--warn); }
|
|
132
|
+
.shot .st.st-approved, .shot .st.st-published { color: var(--good); border-color: var(--good); }
|
|
133
|
+
.shot .cap { display: block; padding: 0.45rem 0.6rem 0.55rem; font-size: 0.83rem; }
|
|
134
|
+
.shot .cap .ti { display: block; font-weight: 600; overflow-wrap: anywhere; }
|
|
135
|
+
.shot .cap .ft { margin-top: 0.25rem; display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: center; color: var(--muted); font-size: 0.72rem; }
|
|
136
|
+
.chip {
|
|
137
|
+
display: inline-block;
|
|
138
|
+
border: 1px solid var(--track);
|
|
139
|
+
border-radius: 4px;
|
|
140
|
+
padding: 0 0.3rem;
|
|
141
|
+
font-size: 0.7rem;
|
|
142
|
+
line-height: 1.4;
|
|
143
|
+
color: var(--muted);
|
|
144
|
+
}
|
|
145
|
+
.chip.tag { border-style: dashed; }
|
|
146
|
+
.chip.st-published { color: var(--good); border-color: var(--good); }
|
|
147
|
+
.grid-empty {
|
|
148
|
+
background: var(--card);
|
|
149
|
+
border: 1px dashed var(--track);
|
|
150
|
+
border-radius: 10px;
|
|
151
|
+
padding: 0.85rem 1.25rem;
|
|
152
|
+
text-align: center;
|
|
153
|
+
color: var(--muted);
|
|
154
|
+
margin-bottom: 0.75rem;
|
|
155
|
+
}
|
|
156
|
+
.foot { color: var(--muted); font-size: 0.72rem; margin-top: 1rem; }
|
|
157
|
+
.drawer {
|
|
158
|
+
position: fixed;
|
|
159
|
+
top: 0;
|
|
160
|
+
right: 0;
|
|
161
|
+
bottom: 0;
|
|
162
|
+
width: min(430px, 94vw);
|
|
163
|
+
background: var(--card);
|
|
164
|
+
border-left: 1px solid var(--track);
|
|
165
|
+
box-shadow: -6px 0 18px rgba(0, 0, 0, 0.08);
|
|
166
|
+
padding: 1rem 1.1rem 1.5rem;
|
|
167
|
+
overflow-y: auto;
|
|
168
|
+
z-index: 10;
|
|
169
|
+
}
|
|
170
|
+
.drawer[hidden] { display: none; }
|
|
171
|
+
.drawer .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.5rem; }
|
|
172
|
+
.drawer h2 {
|
|
173
|
+
font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
|
|
174
|
+
font-size: 1.1rem;
|
|
175
|
+
font-weight: 600;
|
|
176
|
+
margin: 0 0 0.2rem;
|
|
177
|
+
overflow-wrap: anywhere;
|
|
178
|
+
}
|
|
179
|
+
.drawer h3 {
|
|
180
|
+
font-size: 0.72rem;
|
|
181
|
+
text-transform: uppercase;
|
|
182
|
+
letter-spacing: 0.05em;
|
|
183
|
+
color: var(--muted);
|
|
184
|
+
margin: 1rem 0 0.35rem;
|
|
185
|
+
font-weight: 600;
|
|
186
|
+
}
|
|
187
|
+
.drawer .meta { color: var(--muted); font-size: 0.8rem; }
|
|
188
|
+
.drawer .body-text { white-space: pre-wrap; font-size: 0.88rem; overflow-wrap: anywhere; }
|
|
189
|
+
.drawer .moves { display: flex; gap: 0.35rem; flex-wrap: wrap; margin-top: 0.35rem; }
|
|
190
|
+
.drawer .error { color: var(--warn); font-size: 0.8rem; margin: 0.4rem 0 0; }
|
|
191
|
+
.drawer .thumbs { display: flex; gap: 0.4rem; flex-wrap: wrap; }
|
|
192
|
+
.drawer .thumbs img {
|
|
193
|
+
width: 84px;
|
|
194
|
+
height: 84px;
|
|
195
|
+
object-fit: cover;
|
|
196
|
+
border: 1px solid var(--track);
|
|
197
|
+
border-radius: 4px;
|
|
198
|
+
}
|
|
199
|
+
.variant {
|
|
200
|
+
border: 1px solid var(--track);
|
|
201
|
+
border-radius: 6px;
|
|
202
|
+
padding: 0.45rem 0.6rem;
|
|
203
|
+
margin-bottom: 0.45rem;
|
|
204
|
+
font-size: 0.83rem;
|
|
205
|
+
}
|
|
206
|
+
.variant .vh { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.25rem; }
|
|
207
|
+
.variant .vh .name { font-weight: 600; }
|
|
208
|
+
.variant .vb { white-space: pre-wrap; color: var(--ink); overflow-wrap: anywhere; }
|
|
209
|
+
.variant a { color: var(--accent); }
|
|
210
|
+
.empty { color: var(--muted); font-style: italic; }
|
|
211
|
+
.demo-banner {
|
|
212
|
+
display: flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
justify-content: space-between;
|
|
215
|
+
gap: 0.75rem;
|
|
216
|
+
margin: 0 0 0.85rem;
|
|
217
|
+
padding: 0.5rem 0.65rem;
|
|
218
|
+
border: 1px solid var(--accent);
|
|
219
|
+
border-radius: 6px;
|
|
220
|
+
background: color-mix(in srgb, var(--card) 88%, var(--accent));
|
|
221
|
+
color: var(--ink);
|
|
222
|
+
font-size: 0.8rem;
|
|
223
|
+
}
|
|
224
|
+
.demo-banner[hidden] { display: none; }
|
|
225
|
+
.demo-banner strong { font-weight: 700; }
|
|
226
|
+
.demo-reset {
|
|
227
|
+
flex: none;
|
|
228
|
+
padding: 0.25rem 0.5rem;
|
|
229
|
+
border: 1px solid var(--accent);
|
|
230
|
+
border-radius: 6px;
|
|
231
|
+
background: var(--card);
|
|
232
|
+
color: var(--ink);
|
|
233
|
+
cursor: pointer;
|
|
234
|
+
font: inherit;
|
|
235
|
+
}
|
|
236
|
+
.demo-reset:hover { border-color: var(--ink); }
|
|
237
|
+
</style>
|
|
238
|
+
</head>
|
|
239
|
+
<body>
|
|
240
|
+
<main>
|
|
241
|
+
<div class="demo-banner" data-gezel-demo-banner hidden>
|
|
242
|
+
<span><strong>Demo mode</strong> — sample data stays in this page.</span>
|
|
243
|
+
<button type="button" class="demo-reset" onclick="location.reload()">Reset demo</button>
|
|
244
|
+
</div>
|
|
245
|
+
<p class="note" id="browser-note" hidden>
|
|
246
|
+
Viewing from a browser tab — the gallery stays live, but moving posts happens in the app's Output pane.
|
|
247
|
+
</p>
|
|
248
|
+
<div class="head">
|
|
249
|
+
<div>
|
|
250
|
+
<h1 id="title">Image feed</h1>
|
|
251
|
+
<p class="sub" id="sub">Loading the gallery…</p>
|
|
252
|
+
</div>
|
|
253
|
+
<button type="button" class="key" id="toggle-archived" aria-pressed="false">Show archived</button>
|
|
254
|
+
</div>
|
|
255
|
+
<p class="hint" id="corpus-hint" hidden>
|
|
256
|
+
Connected feeds are syncing — reception reports read from the project's artifacts.
|
|
257
|
+
</p>
|
|
258
|
+
<div class="grid-empty" id="grid-empty" hidden>
|
|
259
|
+
No posts yet — ask your Omroeper for the first image of the feed.
|
|
260
|
+
</div>
|
|
261
|
+
<div class="grid" id="grid"></div>
|
|
262
|
+
<p class="foot" id="mode-line"></p>
|
|
263
|
+
</main>
|
|
264
|
+
<aside class="drawer" id="drawer" hidden>
|
|
265
|
+
<div class="top">
|
|
266
|
+
<div>
|
|
267
|
+
<h2 id="d-title"></h2>
|
|
268
|
+
<p class="meta" id="d-meta"></p>
|
|
269
|
+
</div>
|
|
270
|
+
<button type="button" class="key" id="d-close">Close</button>
|
|
271
|
+
</div>
|
|
272
|
+
<h3>Move to</h3>
|
|
273
|
+
<div class="moves" id="d-moves"></div>
|
|
274
|
+
<p class="error" id="d-error" hidden></p>
|
|
275
|
+
<h3>Media</h3>
|
|
276
|
+
<div class="thumbs" id="d-thumbs"></div>
|
|
277
|
+
<p class="meta" id="d-media"></p>
|
|
278
|
+
<h3>Post</h3>
|
|
279
|
+
<div class="body-text" id="d-body"></div>
|
|
280
|
+
<h3>Variants</h3>
|
|
281
|
+
<div id="d-variants"></div>
|
|
282
|
+
</aside>
|
|
283
|
+
<script>
|
|
284
|
+
/* gezel-page-demo-stub v1 */
|
|
285
|
+
/*
|
|
286
|
+
* The canonical demo stub for Gezel type pages. MIT License.
|
|
287
|
+
*
|
|
288
|
+
* Paste this file's bytes verbatim into a <script> block ahead of the
|
|
289
|
+
* page's own code, then call makeDemoGezel({ page, tools, data }) with the
|
|
290
|
+
* page's demo handlers. Served by Gezel, the real window.gezel is already
|
|
291
|
+
* injected and the stub steps aside; opened as a raw file (the live demos
|
|
292
|
+
* on gezelgilde.com), it installs a window.gezel whose tools and data are
|
|
293
|
+
* the page-supplied handler maps — one code path in every mode. `tools`
|
|
294
|
+
* and `data` map a tool name / declared read path to a function; data
|
|
295
|
+
* handlers back read() and list(), and url() returns the handler's value
|
|
296
|
+
* or passes a data: URI through. See docs/page-authoring.md.
|
|
297
|
+
*/
|
|
298
|
+
(function () {
|
|
299
|
+
'use strict';
|
|
300
|
+
window.makeDemoGezel = function (opts) {
|
|
301
|
+
if (window.gezel) return window.gezel;
|
|
302
|
+
var page = (opts && opts.page) || {};
|
|
303
|
+
var tools = (opts && opts.tools) || {};
|
|
304
|
+
var data = (opts && opts.data) || {};
|
|
305
|
+
var themeListeners = [];
|
|
306
|
+
var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
307
|
+
var ui = {
|
|
308
|
+
theme: { mode: media && media.matches ? 'dark' : 'light' },
|
|
309
|
+
onTheme: function (cb) {
|
|
310
|
+
themeListeners.push(cb);
|
|
311
|
+
return function () {
|
|
312
|
+
var at = themeListeners.indexOf(cb);
|
|
313
|
+
if (at >= 0) themeListeners.splice(at, 1);
|
|
314
|
+
};
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
if (media && media.addEventListener) {
|
|
318
|
+
media.addEventListener('change', function (ev) {
|
|
319
|
+
ui.theme = { mode: ev.matches ? 'dark' : 'light' };
|
|
320
|
+
themeListeners.slice().forEach(function (cb) { cb(ui.theme); });
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
function fail(code, message) {
|
|
324
|
+
var err = new Error(message);
|
|
325
|
+
err.code = code;
|
|
326
|
+
return Promise.reject(err);
|
|
327
|
+
}
|
|
328
|
+
function run(map, key, arg) {
|
|
329
|
+
if (!Object.prototype.hasOwnProperty.call(map, key)) return null;
|
|
330
|
+
return Promise.resolve().then(function () { return map[key](arg); });
|
|
331
|
+
}
|
|
332
|
+
window.gezel = {
|
|
333
|
+
page: {
|
|
334
|
+
api: 1,
|
|
335
|
+
projectId: 'demo',
|
|
336
|
+
source: 'type',
|
|
337
|
+
entry: page.entry || 'index.html',
|
|
338
|
+
typeName: page.typeName || 'demo',
|
|
339
|
+
params: page.params || {},
|
|
340
|
+
mode: 'demo',
|
|
341
|
+
},
|
|
342
|
+
tools: {
|
|
343
|
+
list: function () { return Promise.resolve(Object.keys(tools)); },
|
|
344
|
+
invoke: function (name, input) {
|
|
345
|
+
var call = run(tools, name, input || {});
|
|
346
|
+
if (!call) return fail('not-allowed', "The demo does not handle the tool '" + name + "'.");
|
|
347
|
+
return call.then(function (output) { return { output: output }; });
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
data: {
|
|
351
|
+
read: function (path, o) {
|
|
352
|
+
return run(data, path, o || {}) || fail('not-allowed', "The demo has no data for '" + path + "'.");
|
|
353
|
+
},
|
|
354
|
+
list: function (path, o) {
|
|
355
|
+
return run(data, path, o || {}) || Promise.resolve([]);
|
|
356
|
+
},
|
|
357
|
+
watch: function () { return function () {}; },
|
|
358
|
+
url: function (path) {
|
|
359
|
+
if (Object.prototype.hasOwnProperty.call(data, path)) return String(data[path]({}));
|
|
360
|
+
return typeof path === 'string' && path.indexOf('data:') === 0 ? path : '';
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
ui: ui,
|
|
364
|
+
refresh: function () {},
|
|
365
|
+
};
|
|
366
|
+
return window.gezel;
|
|
367
|
+
};
|
|
368
|
+
})();
|
|
369
|
+
</script>
|
|
370
|
+
<script>
|
|
371
|
+
(function () {
|
|
372
|
+
'use strict';
|
|
373
|
+
var STAGES = ['idea', 'draft', 'in-review', 'approved', 'scheduled', 'published'];
|
|
374
|
+
var DAY = 24 * 60 * 60 * 1000;
|
|
375
|
+
|
|
376
|
+
function legalNext(from) {
|
|
377
|
+
if (from === 'archived') return [];
|
|
378
|
+
var at = STAGES.indexOf(from);
|
|
379
|
+
var next = at >= 0 && at < STAGES.length - 1 ? [STAGES[at + 1]] : [];
|
|
380
|
+
return next.concat(['archived']);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ── demo dataset (used only when the page opens as a raw file) ──
|
|
384
|
+
function svgUri(bg, fg, shape) {
|
|
385
|
+
var art;
|
|
386
|
+
if (shape === 'arch') {
|
|
387
|
+
art = '<path d="M100 320 L100 190 A100 100 0 0 1 300 190 L300 320 Z" fill="' + fg + '"/>';
|
|
388
|
+
} else if (shape === 'bars') {
|
|
389
|
+
art = '<rect x="80" y="120" width="240" height="34" rx="4" fill="' + fg + '"/>' +
|
|
390
|
+
'<rect x="80" y="183" width="240" height="34" rx="4" fill="' + fg + '" opacity="0.75"/>' +
|
|
391
|
+
'<rect x="80" y="246" width="240" height="34" rx="4" fill="' + fg + '" opacity="0.5"/>';
|
|
392
|
+
} else {
|
|
393
|
+
art = '<circle cx="200" cy="185" r="95" fill="' + fg + '"/>' +
|
|
394
|
+
'<rect x="70" y="305" width="260" height="12" rx="4" fill="' + fg + '" opacity="0.55"/>';
|
|
395
|
+
}
|
|
396
|
+
var svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">' +
|
|
397
|
+
'<rect width="400" height="400" fill="' + bg + '"/>' + art + '</svg>';
|
|
398
|
+
return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
|
|
399
|
+
}
|
|
400
|
+
function demoPost(daysAgo, slug, title, status, platforms, extra) {
|
|
401
|
+
var created = new Date(Date.now() - daysAgo * DAY).toISOString().slice(0, 10);
|
|
402
|
+
var post = {
|
|
403
|
+
id: created + '-' + slug,
|
|
404
|
+
title: title,
|
|
405
|
+
status: status,
|
|
406
|
+
platforms: platforms,
|
|
407
|
+
created: created,
|
|
408
|
+
body: extra.body || 'A picture from the studio.',
|
|
409
|
+
variants: extra.variants || {},
|
|
410
|
+
media: extra.cover ? ['cover.svg'] : [],
|
|
411
|
+
cover: extra.cover || null,
|
|
412
|
+
};
|
|
413
|
+
if (extra.scheduledFor) post.scheduledFor = extra.scheduledFor;
|
|
414
|
+
if (extra.campaign) post.campaign = extra.campaign;
|
|
415
|
+
return post;
|
|
416
|
+
}
|
|
417
|
+
var demoPosts = [
|
|
418
|
+
demoPost(0, 'glaze-tests-week-33', 'Glaze tests, week 33', 'idea', ['instagram'], {
|
|
419
|
+
body: 'Notion: a carousel of this week’s glaze tests, ugly ones included. People love the misses.',
|
|
420
|
+
}),
|
|
421
|
+
demoPost(1, 'the-saltpan-series', 'The saltpan series', 'draft', ['instagram', 'bluesky'], {
|
|
422
|
+
campaign: 'saltpan',
|
|
423
|
+
cover: svgUri('#e8ddcb', '#b5651d', 'circle'),
|
|
424
|
+
body: 'First proper look at the saltpan series — six vessels glazed from one bucket of coastal slip.',
|
|
425
|
+
variants: {
|
|
426
|
+
instagram: { charCount: 214, body: 'Six vessels, one bucket of coastal slip. The saltpan series is out of the kiln and sitting in the morning light.' },
|
|
427
|
+
},
|
|
428
|
+
}),
|
|
429
|
+
demoPost(3, 'studio-shelves-before-the-kiln', 'Studio shelves, before the kiln', 'in-review', ['instagram'], {
|
|
430
|
+
cover: svgUri('#26352d', '#a7b89a', 'bars'),
|
|
431
|
+
body: 'The shelves the night before a firing — everything bone dry, everything still a maybe.',
|
|
432
|
+
variants: {
|
|
433
|
+
instagram: { charCount: 156, body: 'The night before a firing. Everything bone dry, everything still a maybe.' },
|
|
434
|
+
},
|
|
435
|
+
}),
|
|
436
|
+
demoPost(5, 'three-mugs-one-morning', 'Three mugs, one morning', 'approved', ['instagram'], {
|
|
437
|
+
cover: svgUri('#f5ede2', '#8d694d', 'arch'),
|
|
438
|
+
body: 'Three mugs from the same board, photographed with the first coffee they ever held.',
|
|
439
|
+
variants: {
|
|
440
|
+
instagram: { charCount: 132, body: 'Three mugs from the same board, and the first coffee they ever held.' },
|
|
441
|
+
},
|
|
442
|
+
}),
|
|
443
|
+
demoPost(7, 'saltpan-series-first-firing', 'Saltpan series — first firing', 'scheduled', ['instagram', 'bluesky'], {
|
|
444
|
+
campaign: 'saltpan',
|
|
445
|
+
cover: svgUri('#19323c', '#9bb8b3', 'circle'),
|
|
446
|
+
scheduledFor: new Date(Date.now() + 2 * DAY).toISOString().slice(0, 10),
|
|
447
|
+
body: 'Kiln-opening shots from the first saltpan firing, scheduled for Thursday morning.',
|
|
448
|
+
variants: {
|
|
449
|
+
instagram: { charCount: 141, body: 'Kiln opening, saltpan firing number one. Thursday morning, first light.' },
|
|
450
|
+
bluesky: { charCount: 129, body: 'Saltpan firing no. 1 opens Thursday. Kiln shots to follow.' },
|
|
451
|
+
},
|
|
452
|
+
}),
|
|
453
|
+
demoPost(10, 'open-studio-weekend', 'Open studio weekend', 'published', ['instagram'], {
|
|
454
|
+
cover: svgUri('#ece5da', '#4a7c59', 'bars'),
|
|
455
|
+
body: 'Photos from open studio weekend — the bench, the visitors, and the shelf that sold out by noon.',
|
|
456
|
+
variants: {
|
|
457
|
+
instagram: { charCount: 168, publishedAt: new Date(Date.now() - 9 * DAY).toISOString(), permalink: 'https://www.instagram.com/p/demo3xample/', body: 'Open studio weekend: the bench, the visitors, and the shelf that sold out by noon. Thank you for coming.' },
|
|
458
|
+
},
|
|
459
|
+
}),
|
|
460
|
+
demoPost(24, 'spring-market-recap', 'Spring market recap (superseded)', 'archived', ['instagram'], {
|
|
461
|
+
cover: svgUri('#e0d6c6', '#7a7166', 'arch'),
|
|
462
|
+
body: 'Kept for the record: the spring market recap.',
|
|
463
|
+
}),
|
|
464
|
+
];
|
|
465
|
+
function demoFind(id) {
|
|
466
|
+
for (var i = 0; i < demoPosts.length; i += 1) {
|
|
467
|
+
if (demoPosts[i].id === id) return demoPosts[i];
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
function demoIndex() {
|
|
472
|
+
return {
|
|
473
|
+
version: 1,
|
|
474
|
+
posts: demoPosts.map(function (post) {
|
|
475
|
+
var entry = {
|
|
476
|
+
id: post.id,
|
|
477
|
+
title: post.title,
|
|
478
|
+
status: post.status,
|
|
479
|
+
platforms: post.platforms,
|
|
480
|
+
created: post.created,
|
|
481
|
+
};
|
|
482
|
+
if (post.scheduledFor) entry.scheduledFor = post.scheduledFor;
|
|
483
|
+
if (post.campaign) entry.campaign = post.campaign;
|
|
484
|
+
return entry;
|
|
485
|
+
}),
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
var demoData = {
|
|
489
|
+
'posts/index.json': function () { return demoIndex(); },
|
|
490
|
+
data: function () {
|
|
491
|
+
return [{ name: 'instagram-media', kind: 'dir', size: 0, mtime: new Date().toISOString() }];
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
demoPosts.forEach(function (post) {
|
|
495
|
+
if (!post.cover) return;
|
|
496
|
+
demoData['posts/' + post.id + '/media'] = function () {
|
|
497
|
+
return [{ name: 'cover.svg', kind: 'file', size: 0, mtime: new Date().toISOString() }];
|
|
498
|
+
};
|
|
499
|
+
demoData['posts/' + post.id + '/media/cover.svg'] = function () { return post.cover; };
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
makeDemoGezel({
|
|
503
|
+
page: {
|
|
504
|
+
entry: 'gallery/index.html',
|
|
505
|
+
typeName: 'Image Feed',
|
|
506
|
+
params: {
|
|
507
|
+
brand: 'Veld Ceramics',
|
|
508
|
+
cadence: '4 images a week',
|
|
509
|
+
visualStyle: 'Natural light, honest clay, no filters.',
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
tools: {
|
|
513
|
+
page_set_status: function (input) {
|
|
514
|
+
var post = demoFind(input && input.id);
|
|
515
|
+
if (!post) throw new Error("No post '" + (input && input.id) + "' in the demo gallery.");
|
|
516
|
+
var to = input.status;
|
|
517
|
+
if (post.status !== to && legalNext(post.status).indexOf(to) < 0) {
|
|
518
|
+
var next = legalNext(post.status);
|
|
519
|
+
throw new Error(
|
|
520
|
+
"Cannot move '" + post.id + "' from " + post.status + ' to ' + to +
|
|
521
|
+
' — posts move one stage at a time.' +
|
|
522
|
+
(next.length ? ' Legal next: ' + next.join(', ') + '.' : " '" + post.status + "' is final.")
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
post.status = to;
|
|
526
|
+
return { id: post.id, status: post.status, summary: 'Moved.' };
|
|
527
|
+
},
|
|
528
|
+
page_get_post: function (input) {
|
|
529
|
+
var post = demoFind(input && input.id);
|
|
530
|
+
if (!post) throw new Error("No post '" + (input && input.id) + "' in the demo gallery.");
|
|
531
|
+
return { id: post.id, status: post.status, post: post, summary: post.title };
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
data: demoData,
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
// ── one code path from here: window.gezel exists in every mode ──
|
|
538
|
+
var demoMode = gezel.page.mode === 'demo';
|
|
539
|
+
var browserMode = gezel.page.mode === 'browser';
|
|
540
|
+
var params = gezel.page.params || {};
|
|
541
|
+
var showArchived = false;
|
|
542
|
+
var openPostId = null;
|
|
543
|
+
var lastIndex = { posts: [] };
|
|
544
|
+
var covers = {};
|
|
545
|
+
|
|
546
|
+
function applyTheme(mode) {
|
|
547
|
+
document.documentElement.setAttribute('data-theme', mode === 'dark' ? 'dark' : 'light');
|
|
548
|
+
}
|
|
549
|
+
applyTheme(gezel.ui.theme.mode);
|
|
550
|
+
gezel.ui.onTheme(function (theme) { applyTheme(theme.mode); });
|
|
551
|
+
|
|
552
|
+
if (demoMode) document.querySelector('[data-gezel-demo-banner]').hidden = false;
|
|
553
|
+
if (browserMode) document.getElementById('browser-note').hidden = false;
|
|
554
|
+
|
|
555
|
+
function esc(value) {
|
|
556
|
+
return String(value).replace(/[&<>"]/g, function (ch) {
|
|
557
|
+
return { '&': '&', '<': '<', '>': '>', '"': '"' }[ch];
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
function el(id) { return document.getElementById(id); }
|
|
561
|
+
|
|
562
|
+
var brand = typeof params.brand === 'string' && params.brand ? params.brand : gezel.page.typeName;
|
|
563
|
+
el('title').textContent = brand;
|
|
564
|
+
el('mode-line').textContent = 'mode: ' + gezel.page.mode;
|
|
565
|
+
document.title = brand + ' — image feed gallery';
|
|
566
|
+
|
|
567
|
+
function parseFront(text) {
|
|
568
|
+
var lines = String(text).split(/\r?\n/);
|
|
569
|
+
if ((lines[0] || '').trim() !== '---') return { fields: {}, body: String(text) };
|
|
570
|
+
var fields = {};
|
|
571
|
+
for (var i = 1; i < lines.length; i += 1) {
|
|
572
|
+
if (lines[i].trim() === '---') {
|
|
573
|
+
return { fields: fields, body: lines.slice(i + 1).join('\n').replace(/^\n/, '') };
|
|
574
|
+
}
|
|
575
|
+
var sep = lines[i].indexOf(':');
|
|
576
|
+
if (sep <= 0) continue;
|
|
577
|
+
var key = lines[i].slice(0, sep).trim();
|
|
578
|
+
var raw = lines[i].slice(sep + 1).trim();
|
|
579
|
+
if (raw.charAt(0) === '[' && raw.charAt(raw.length - 1) === ']') {
|
|
580
|
+
fields[key] = raw.slice(1, -1).split(',').map(function (part) { return part.trim(); }).filter(Boolean);
|
|
581
|
+
} else {
|
|
582
|
+
fields[key] = raw;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return { fields: {}, body: String(text) };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function isImage(name) {
|
|
589
|
+
return /\.(png|jpe?g|webp|gif|svg|avif)$/i.test(name);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function resolveCover(id) {
|
|
593
|
+
if (Object.prototype.hasOwnProperty.call(covers, id)) return Promise.resolve(covers[id]);
|
|
594
|
+
return gezel.data
|
|
595
|
+
.list('posts/' + id + '/media')
|
|
596
|
+
.catch(function () { return []; })
|
|
597
|
+
.then(function (entries) {
|
|
598
|
+
var first = null;
|
|
599
|
+
for (var i = 0; i < entries.length; i += 1) {
|
|
600
|
+
if (entries[i].kind !== 'dir' && isImage(entries[i].name)) { first = entries[i].name; break; }
|
|
601
|
+
}
|
|
602
|
+
covers[id] = first ? gezel.data.url('posts/' + id + '/media/' + first) : '';
|
|
603
|
+
return covers[id];
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function renderGrid(index) {
|
|
608
|
+
lastIndex = index && Array.isArray(index.posts) ? index : { posts: [] };
|
|
609
|
+
var posts = lastIndex.posts;
|
|
610
|
+
var visible = posts.filter(function (post) { return showArchived || post.status !== 'archived'; });
|
|
611
|
+
var live = posts.filter(function (post) { return post.status !== 'archived'; });
|
|
612
|
+
var published = posts.filter(function (post) { return post.status === 'published'; }).length;
|
|
613
|
+
var cadence = typeof params.cadence === 'string' && params.cadence ? params.cadence : '';
|
|
614
|
+
el('sub').textContent =
|
|
615
|
+
(cadence ? 'Aiming for ' + cadence + ' · ' : '') +
|
|
616
|
+
live.length + ' post' + (live.length === 1 ? '' : 's') + ' in flight · ' + published + ' published';
|
|
617
|
+
el('grid-empty').hidden = posts.length > 0;
|
|
618
|
+
|
|
619
|
+
el('grid').innerHTML = visible
|
|
620
|
+
.map(function (post) {
|
|
621
|
+
var chips = (post.platforms || [])
|
|
622
|
+
.map(function (platform) { return '<span class="chip">' + esc(platform) + '</span>'; })
|
|
623
|
+
.join('');
|
|
624
|
+
if (post.campaign) chips += '<span class="chip tag">' + esc(post.campaign) + '</span>';
|
|
625
|
+
var when = post.status === 'scheduled' && post.scheduledFor ? 'for ' + esc(String(post.scheduledFor).slice(0, 10)) : esc(String(post.created || '').slice(0, 10));
|
|
626
|
+
return (
|
|
627
|
+
'<button type="button" class="shot" data-post="' + esc(post.id) + '">' +
|
|
628
|
+
'<span class="pic" data-pic="' + esc(post.id) + '"><span class="tcard">' + esc(post.title || post.id) + '</span></span>' +
|
|
629
|
+
'<span class="st st-' + esc(post.status) + '">' + esc(post.status) + '</span>' +
|
|
630
|
+
'<span class="cap"><span class="ti">' + esc(post.title || post.id) + '</span>' +
|
|
631
|
+
'<span class="ft">' + chips + '<span>' + when + '</span></span></span>' +
|
|
632
|
+
'</button>'
|
|
633
|
+
);
|
|
634
|
+
})
|
|
635
|
+
.join('');
|
|
636
|
+
|
|
637
|
+
visible.forEach(function (post) {
|
|
638
|
+
resolveCover(post.id).then(function (src) {
|
|
639
|
+
if (!src) return;
|
|
640
|
+
var pic = document.querySelector('[data-pic="' + post.id + '"]');
|
|
641
|
+
if (pic) {
|
|
642
|
+
pic.innerHTML = '<img alt="' + esc(post.title || post.id) + '" src="' + esc(src) + '" />';
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function loadGrid() {
|
|
649
|
+
return gezel.data
|
|
650
|
+
.read('posts/index.json')
|
|
651
|
+
.then(function (index) { renderGrid(index); })
|
|
652
|
+
.catch(function () { renderGrid({ posts: [] }); });
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function setDrawerError(message) {
|
|
656
|
+
var node = el('d-error');
|
|
657
|
+
node.textContent = message || '';
|
|
658
|
+
node.hidden = !message;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function renderDrawer(post) {
|
|
662
|
+
el('drawer').hidden = false;
|
|
663
|
+
el('d-title').textContent = post.title || post.id;
|
|
664
|
+
var meta = [post.status, 'created ' + String(post.created || '').slice(0, 10)];
|
|
665
|
+
if (post.scheduledFor) meta.push('scheduled for ' + String(post.scheduledFor).slice(0, 10));
|
|
666
|
+
if (post.campaign) meta.push('campaign: ' + post.campaign);
|
|
667
|
+
el('d-meta').textContent = meta.join(' · ');
|
|
668
|
+
el('d-body').textContent = post.body || '(no caption yet)';
|
|
669
|
+
|
|
670
|
+
var moves = legalNext(post.status);
|
|
671
|
+
el('d-moves').innerHTML =
|
|
672
|
+
moves.length === 0
|
|
673
|
+
? '<span class="empty">' + esc(post.status) + ' is the end of the line.</span>'
|
|
674
|
+
: moves
|
|
675
|
+
.map(function (stage) {
|
|
676
|
+
return '<button type="button" class="key" data-move="' + esc(stage) + '">' + esc(stage) + '</button>';
|
|
677
|
+
})
|
|
678
|
+
.join('');
|
|
679
|
+
if (browserMode && moves.length > 0) {
|
|
680
|
+
el('d-moves').innerHTML = '<span class="empty">Open the Output pane in the app to move this post.</span>';
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
var media = post.media || [];
|
|
684
|
+
el('d-media').textContent = media.length === 0 ? 'No media attached yet.' : media.join(', ');
|
|
685
|
+
el('d-thumbs').innerHTML = media
|
|
686
|
+
.filter(isImage)
|
|
687
|
+
.map(function (name) {
|
|
688
|
+
var src = gezel.data.url('posts/' + post.id + '/media/' + name);
|
|
689
|
+
return src ? '<img alt="' + esc(name) + '" src="' + esc(src) + '" />' : '';
|
|
690
|
+
})
|
|
691
|
+
.join('');
|
|
692
|
+
|
|
693
|
+
var variants = post.variants || {};
|
|
694
|
+
var names = Object.keys(variants);
|
|
695
|
+
el('d-variants').innerHTML =
|
|
696
|
+
names.length === 0
|
|
697
|
+
? '<p class="meta empty">No platform variants drafted yet.</p>'
|
|
698
|
+
: names
|
|
699
|
+
.map(function (name) {
|
|
700
|
+
var variant = variants[name] || {};
|
|
701
|
+
var head = '<span class="name">' + esc(name) + '</span>' +
|
|
702
|
+
'<span class="chip">' + esc(String(variant.charCount || 0)) + ' chars</span>';
|
|
703
|
+
if (variant.publishedAt) head += '<span class="chip st-published">live</span>';
|
|
704
|
+
if (variant.permalink) {
|
|
705
|
+
head += '<a href="' + esc(variant.permalink) + '" rel="noreferrer">permalink</a>';
|
|
706
|
+
}
|
|
707
|
+
return '<div class="variant"><div class="vh">' + head + '</div>' +
|
|
708
|
+
'<div class="vb">' + esc(variant.body || '') + '</div></div>';
|
|
709
|
+
})
|
|
710
|
+
.join('');
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function fallbackDetail(id) {
|
|
714
|
+
return gezel.data.read('posts/' + id + '/post.md').then(function (raw) {
|
|
715
|
+
var parsed = parseFront(raw);
|
|
716
|
+
var post = { id: id };
|
|
717
|
+
Object.keys(parsed.fields).forEach(function (key) { post[key] = parsed.fields[key]; });
|
|
718
|
+
post.status = String(parsed.fields.status || 'idea');
|
|
719
|
+
post.platforms = [].concat(parsed.fields.platforms || []);
|
|
720
|
+
post.body = parsed.body.trim();
|
|
721
|
+
post.variants = {};
|
|
722
|
+
post.media = [];
|
|
723
|
+
return gezel.data
|
|
724
|
+
.list('posts/' + id + '/variants')
|
|
725
|
+
.catch(function () { return []; })
|
|
726
|
+
.then(function (entries) {
|
|
727
|
+
var files = entries.filter(function (entry) { return entry.kind !== 'dir' && /\.md$/.test(entry.name); });
|
|
728
|
+
return Promise.all(
|
|
729
|
+
files.map(function (entry) {
|
|
730
|
+
return gezel.data
|
|
731
|
+
.read('posts/' + id + '/variants/' + entry.name)
|
|
732
|
+
.then(function (variantRaw) {
|
|
733
|
+
var variantDoc = parseFront(variantRaw);
|
|
734
|
+
var body = variantDoc.body.trim();
|
|
735
|
+
var variant = { charCount: Number(variantDoc.fields.charCount) || body.length, body: body };
|
|
736
|
+
['publishedAt', 'permalink', 'postId', 'corpusRef'].forEach(function (key) {
|
|
737
|
+
if (variantDoc.fields[key]) variant[key] = String(variantDoc.fields[key]);
|
|
738
|
+
});
|
|
739
|
+
post.variants[entry.name.replace(/\.md$/, '')] = variant;
|
|
740
|
+
})
|
|
741
|
+
.catch(function () {});
|
|
742
|
+
}),
|
|
743
|
+
);
|
|
744
|
+
})
|
|
745
|
+
.then(function () {
|
|
746
|
+
return gezel.data.list('posts/' + id + '/media').catch(function () { return []; });
|
|
747
|
+
})
|
|
748
|
+
.then(function (entries) {
|
|
749
|
+
post.media = entries
|
|
750
|
+
.filter(function (entry) { return entry.kind !== 'dir'; })
|
|
751
|
+
.map(function (entry) { return entry.name; });
|
|
752
|
+
return post;
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function openPost(id) {
|
|
758
|
+
openPostId = id;
|
|
759
|
+
setDrawerError('');
|
|
760
|
+
gezel.tools
|
|
761
|
+
.invoke('page_get_post', { id: id })
|
|
762
|
+
.then(function (result) {
|
|
763
|
+
if (openPostId === id) renderDrawer(result.output.post || result.output);
|
|
764
|
+
})
|
|
765
|
+
.catch(function (err) {
|
|
766
|
+
if (err && err.code === 'unavailable') {
|
|
767
|
+
fallbackDetail(id)
|
|
768
|
+
.then(function (post) { if (openPostId === id) renderDrawer(post); })
|
|
769
|
+
.catch(function () {
|
|
770
|
+
if (openPostId !== id) return;
|
|
771
|
+
el('drawer').hidden = false;
|
|
772
|
+
el('d-title').textContent = id;
|
|
773
|
+
setDrawerError('Could not load this post right now.');
|
|
774
|
+
});
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
el('drawer').hidden = false;
|
|
778
|
+
el('d-title').textContent = id;
|
|
779
|
+
setDrawerError(err && err.message ? err.message : 'Could not load this post right now.');
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
function closeDrawer() {
|
|
784
|
+
openPostId = null;
|
|
785
|
+
el('drawer').hidden = true;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function movePost(id, status) {
|
|
789
|
+
setDrawerError('');
|
|
790
|
+
gezel.tools
|
|
791
|
+
.invoke('page_set_status', { id: id, status: status })
|
|
792
|
+
.then(function () {
|
|
793
|
+
loadGrid();
|
|
794
|
+
if (openPostId === id) openPost(id);
|
|
795
|
+
})
|
|
796
|
+
.catch(function (err) {
|
|
797
|
+
setDrawerError(err && err.message ? err.message : 'The move was refused.');
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
el('grid').addEventListener('click', function (event) {
|
|
802
|
+
var card = event.target.closest('[data-post]');
|
|
803
|
+
if (card) openPost(card.getAttribute('data-post'));
|
|
804
|
+
});
|
|
805
|
+
el('d-moves').addEventListener('click', function (event) {
|
|
806
|
+
var key = event.target.closest('[data-move]');
|
|
807
|
+
if (key && openPostId) movePost(openPostId, key.getAttribute('data-move'));
|
|
808
|
+
});
|
|
809
|
+
el('d-close').addEventListener('click', closeDrawer);
|
|
810
|
+
document.addEventListener('keydown', function (event) {
|
|
811
|
+
if (event.key === 'Escape') closeDrawer();
|
|
812
|
+
});
|
|
813
|
+
el('toggle-archived').addEventListener('click', function () {
|
|
814
|
+
showArchived = !showArchived;
|
|
815
|
+
this.setAttribute('aria-pressed', showArchived ? 'true' : 'false');
|
|
816
|
+
renderGrid(lastIndex);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
gezel.data
|
|
820
|
+
.list('data', { source: 'artifacts' })
|
|
821
|
+
.then(function (entries) {
|
|
822
|
+
if (entries && entries.length > 0) el('corpus-hint').hidden = false;
|
|
823
|
+
})
|
|
824
|
+
.catch(function () {});
|
|
825
|
+
|
|
826
|
+
loadGrid();
|
|
827
|
+
gezel.data.watch('posts/index.json', function () { loadGrid(); });
|
|
828
|
+
})();
|
|
829
|
+
</script>
|
|
830
|
+
</body>
|
|
831
|
+
</html>
|