@bendyline/gilde 0.2.5 → 0.2.6
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/LICENSE-HankenGrotesk-OFL-1.1.txt +94 -0
- package/authoring/LICENSE-PTSerif-OFL-1.1.txt +94 -0
- package/authoring/page-demo-bootstrap.js +209 -0
- package/authoring/page-demo-injector.mjs +7 -0
- package/authoring/page-demo-typography.css +88 -0
- package/data/craftbook-templates/ch/character-sheet/versions/1.0.4/craftbook.json +213 -0
- package/data/craftbook-templates/ch/character-sheet/versions/1.0.4/test.json +143 -0
- package/data/craftbook-templates/ch/character-turnaround/versions/1.0.4/craftbook.json +254 -0
- package/data/craftbook-templates/ch/character-turnaround/versions/1.0.4/test.json +189 -0
- package/data/craftbook-templates/fa/favicon-set/versions/1.0.5/craftbook.json +282 -0
- package/data/craftbook-templates/fa/favicon-set/versions/1.0.5/test.json +94 -0
- package/data/craftbook-templates/he/hero-image/versions/1.0.5/craftbook.json +287 -0
- package/data/craftbook-templates/he/hero-image/versions/1.0.5/test.json +94 -0
- package/data/craftbook-templates/ic/icon-pack/versions/1.0.5/craftbook.json +279 -0
- package/data/craftbook-templates/ic/icon-pack/versions/1.0.5/test.json +94 -0
- package/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/lo/logo-set/versions/1.0.5/craftbook.json +279 -0
- package/data/craftbook-templates/lo/logo-set/versions/1.0.5/test.json +94 -0
- package/data/craftbook-templates/mo/moodboard/versions/1.0.5/craftbook.json +219 -0
- package/data/craftbook-templates/mo/moodboard/versions/1.0.5/test.json +89 -0
- package/data/craftbook-templates/pa/page-spread/versions/1.0.4/craftbook.json +214 -0
- package/data/craftbook-templates/pa/page-spread/versions/1.0.4/test.json +132 -0
- package/data/craftbook-templates/raw-index.json +1 -1
- package/data/craftbook-templates/sp/sprite-sheet/versions/1.0.5/craftbook.json +269 -0
- package/data/craftbook-templates/sp/sprite-sheet/versions/1.0.5/test.json +94 -0
- package/data/craftbook-templates/ti/tileset-batch/versions/1.0.4/craftbook.json +319 -0
- package/data/craftbook-templates/ti/tileset-batch/versions/1.0.4/test.json +162 -0
- package/data/gezel-templates/il/illustrator/manifest.json +21 -0
- package/data/gezel-templates/il/illustrator/versions/1.0.0/about.md +28 -0
- package/data/gezel-templates/il/illustrator/versions/1.0.0/manifest.json +9 -0
- package/data/gezel-templates/index.json +1 -1
- package/data/gezel-templates/raw-index.json +1 -1
- package/data/image-models/an/animagine-xl-4/manifest.json +2 -0
- package/data/image-models/fl/flux-2-klein-4b-q4/manifest.json +3 -1
- package/data/image-models/index.json +1 -1
- package/data/image-models/ir/iris-3b-f32/manifest.json +4 -2
- package/data/image-models/ir/iris-3b-f32/versions/1.0.2/manifest.json +25 -0
- package/data/image-models/kr/krea-2-turbo-q4/manifest.json +2 -0
- package/data/image-models/kr/krea-2-turbo-q6/manifest.json +2 -0
- package/data/image-models/kr/krea-2-turbo-q8/manifest.json +2 -0
- package/data/image-models/mi/ming-image-0.1-design-bf16/manifest.json +2 -0
- package/data/image-models/mi/ming-image-0.1-design-bf16/versions/1.0.2/manifest.json +50 -0
- package/data/image-models/mo/moss-image-sft-q4/manifest.json +3 -1
- package/data/image-models/mo/moss-image-sft-q4/versions/1.0.0/manifest.json +1 -1
- package/data/image-models/mo/moss-image-sft-q4/versions/1.0.1/manifest.json +37 -0
- package/data/image-models/raw-index.json +1 -1
- package/data/image-models/sd/sd-1.5/manifest.json +2 -0
- package/data/image-models/sd/sd-turbo/manifest.json +2 -0
- package/data/image-models/sd/sdxl-base-1.0/manifest.json +2 -0
- package/data/image-models/sd/sdxl-lightning-4step/manifest.json +2 -0
- package/data/image-models/sd/sdxl-turbo/manifest.json +2 -0
- package/data/project-types/da/data-analysis/versions/1.0.0/about.md +2 -0
- package/data/project-types/da/data-analysis/versions/1.0.0/manifest.json +44 -0
- package/data/project-types/da/data-analysis/versions/1.0.0/pages/dashboard.css +5 -8
- package/data/project-types/da/data-analysis/versions/1.0.0/pages/dashboard.js +11 -31
- package/data/project-types/da/data-analysis/versions/1.0.0/pages/demo.js +9 -0
- package/data/project-types/da/data-analysis/versions/1.0.0/pages/index.html +3 -91
- package/data/project-types/index.json +1 -1
- package/data/project-types/me/media-library/versions/1.0.0/about.md +1 -1
- package/data/project-types/me/media-library/versions/1.0.0/manifest.json +53 -0
- package/data/project-types/me/media-library/versions/1.0.0/pages/gallery.css +3 -14
- package/data/project-types/me/media-library/versions/1.0.0/pages/gallery.js +16 -28
- package/data/project-types/me/media-library/versions/1.0.0/pages/index.html +3 -90
- package/data/project-types/raw-index.json +1 -1
- package/package.json +3 -2
- package/schemas/image-model-identity.schema.json +10 -0
- package/schemas/project-type-version.schema.json +40 -0
|
@@ -11,7 +11,7 @@ Do not assume a filename or modification date proves when or where a photo was
|
|
|
11
11
|
taken. Playback depends on the device's supported formats; unpreviewable files
|
|
12
12
|
remain listed and can be opened through Gezel's existing viewers.
|
|
13
13
|
|
|
14
|
-
The
|
|
14
|
+
The shared Add files control can copy selected files into this workspace when managed writes are enabled. Existing names are preserved by choosing a new name. Browsing does not change files. Hidden folders, dependency folders, and document
|
|
15
15
|
companion folders are skipped. Scans stop after 100 folders or 10,000 files and
|
|
16
16
|
clearly label a partial library. The bundled samples are only a standalone demo;
|
|
17
17
|
they are never inserted into a real project's folder.
|
|
@@ -15,6 +15,59 @@
|
|
|
15
15
|
"path": ".",
|
|
16
16
|
"subtree": true
|
|
17
17
|
}
|
|
18
|
+
],
|
|
19
|
+
"imports": [
|
|
20
|
+
{
|
|
21
|
+
"id": "library",
|
|
22
|
+
"source": "workspace",
|
|
23
|
+
"path": ".",
|
|
24
|
+
"accept": [
|
|
25
|
+
".jpg",
|
|
26
|
+
".jpeg",
|
|
27
|
+
".png",
|
|
28
|
+
".gif",
|
|
29
|
+
".webp",
|
|
30
|
+
".avif",
|
|
31
|
+
".bmp",
|
|
32
|
+
".svg",
|
|
33
|
+
".ico",
|
|
34
|
+
".heic",
|
|
35
|
+
".heif",
|
|
36
|
+
".tif",
|
|
37
|
+
".tiff",
|
|
38
|
+
".dng",
|
|
39
|
+
".raw",
|
|
40
|
+
".cr2",
|
|
41
|
+
".cr3",
|
|
42
|
+
".nef",
|
|
43
|
+
".arw",
|
|
44
|
+
".orf",
|
|
45
|
+
".raf",
|
|
46
|
+
".mp4",
|
|
47
|
+
".webm",
|
|
48
|
+
".mov",
|
|
49
|
+
".m4v",
|
|
50
|
+
".ogv",
|
|
51
|
+
".avi",
|
|
52
|
+
".mkv",
|
|
53
|
+
".mpg",
|
|
54
|
+
".mpeg",
|
|
55
|
+
".mts",
|
|
56
|
+
".m2ts",
|
|
57
|
+
".mp3",
|
|
58
|
+
".wav",
|
|
59
|
+
".ogg",
|
|
60
|
+
".oga",
|
|
61
|
+
".m4a",
|
|
62
|
+
".aac",
|
|
63
|
+
".flac",
|
|
64
|
+
".opus",
|
|
65
|
+
".aif",
|
|
66
|
+
".aiff",
|
|
67
|
+
".wma"
|
|
68
|
+
],
|
|
69
|
+
"maxFileBytes": 268435456
|
|
70
|
+
}
|
|
18
71
|
]
|
|
19
72
|
}
|
|
20
73
|
}
|
|
@@ -39,20 +39,8 @@ dt { color: var(--muted); font-size: .85rem; } dd { margin: 0; font-size: 1.3rem
|
|
|
39
39
|
.view-choices [aria-pressed="true"] { border-color: var(--accent); background: var(--soft); color: var(--accent); box-shadow: inset 0 1px 3px #0002; }
|
|
40
40
|
#gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); list-style: none; gap: 20px; margin: 0; padding: 0; }
|
|
41
41
|
#gallery li { min-width: 0; }
|
|
42
|
-
.media-card { display: flex; flex-direction: column; padding: 0; overflow: hidden; width: 100%; height: 100%; text-align: left; background: var(--surface); border-radius: 6px; }
|
|
43
|
-
.thumbnail { display: flex; position: relative; flex-direction: column; align-items: center; justify-content: center; width: 100%; aspect-ratio: 4 / 3; background: var(--soft); color: var(--accent); overflow: hidden; }
|
|
44
|
-
.thumbnail img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--surface); }
|
|
45
42
|
svg { width: 36px; height: 36px; stroke: currentColor; stroke-width: 1.4; fill: none; stroke-linecap: round; stroke-linejoin: round; }
|
|
46
|
-
.fallback-label { font-size: .8rem; margin-top: 8px; }
|
|
47
|
-
.card-info { padding: 12px; min-width: 0; }
|
|
48
|
-
.file-name { display: block; font-size: .95rem; font-weight: 600; overflow-wrap: anywhere; }
|
|
49
|
-
.file-folder { display: block; font-size: .8rem; color: var(--muted); overflow-wrap: anywhere; margin-block: 2px 8px; }
|
|
50
|
-
.file-meta { display: block; font-size: .75rem; color: var(--muted); }
|
|
51
43
|
#gallery[data-view="list"] { grid-template-columns: 1fr; gap: 8px; }
|
|
52
|
-
[data-view="list"] .media-card { flex-direction: row; align-items: center; }
|
|
53
|
-
[data-view="list"] .thumbnail { flex: 0 0 100px; width: 100px; }
|
|
54
|
-
[data-view="list"] .fallback-label { display: none; }
|
|
55
|
-
[data-view="list"] .file-folder { margin-bottom: 2px; }
|
|
56
44
|
#show-more { display: block; margin: 24px auto; }
|
|
57
45
|
.empty { padding: 40px 20px; text-align: center; border: 1px dashed var(--border); border-radius: 10px; background: var(--surface); }
|
|
58
46
|
.empty p { margin: 12px 0 0; color: var(--muted); }
|
|
@@ -73,8 +61,6 @@ dialog::backdrop { background: #000b; }
|
|
|
73
61
|
#position { font-size: .8rem; color: var(--muted); }
|
|
74
62
|
@media (max-width: 480px) {
|
|
75
63
|
#gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
|
|
76
|
-
.card-info { padding: 8px; }
|
|
77
|
-
.file-name { font-size: .85rem; }
|
|
78
64
|
.counts { gap: 20px; }
|
|
79
65
|
header { align-items: flex-start; }
|
|
80
66
|
.library-heading { align-items: flex-start; flex-direction: column; gap: 4px; }
|
|
@@ -83,3 +69,6 @@ dialog::backdrop { background: #000b; }
|
|
|
83
69
|
.navigation { flex-wrap: wrap; gap: 8px; }
|
|
84
70
|
[data-gezel-demo-banner] { align-items: flex-start; flex-direction: column; }
|
|
85
71
|
}
|
|
72
|
+
|
|
73
|
+
/* Shared components own file presentation; the page owns its layout. */
|
|
74
|
+
#add-files { margin: 20px 0; }
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
|
-
const api = window.makeDemoGezel({ page: { typeName: 'Media Library' } });
|
|
4
|
-
const demoMode = api.page.mode === 'demo';
|
|
5
3
|
const model = window.mediaLibraryFiles;
|
|
6
4
|
const $ = (id) => document.getElementById(id);
|
|
7
5
|
const labels = { image: 'Image', video: 'Video', audio: 'Audio' };
|
|
@@ -12,9 +10,14 @@
|
|
|
12
10
|
['Studio/Evening light.svg', 'evening.svg', 1980], ['Motion/Light study.webm', 'light.webm', 24000],
|
|
13
11
|
['Recordings/Three notes.wav', 'notes.wav', 96044],
|
|
14
12
|
].map(([path, asset, size], i) => ({ path, asset, kind: model.kind(path), size, mtime: 1792368000000 - i * 86400000 }));
|
|
13
|
+
const api = window.gezel || window.makeDemoGezel({ page: { typeName: 'Media Library' }, existingPaths: samples.map(file => file.path) });
|
|
14
|
+
const demoMode = api.page.mode === 'demo';
|
|
15
|
+
const components = api.ui.components;
|
|
16
|
+
const componentCards = [];
|
|
17
|
+
const mountAdder = () => components.fileAdder('#add-files', { target: 'library', onAdded: () => refresh() });
|
|
18
|
+
let adder = mountAdder();
|
|
15
19
|
let files = [], shown = [], visible = 24, view = 'grid', busy = false, again = false, stopped = false, debounce, currentPath = null, previewRevision = 0, focusPath = null;
|
|
16
20
|
const watches = new Map();
|
|
17
|
-
const cards = new Map();
|
|
18
21
|
function element(tag, text, className) { const el = document.createElement(tag); if (text !== undefined) el.textContent = text; if (className) el.className = className; return el; }
|
|
19
22
|
function icon(type) {
|
|
20
23
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
@@ -29,7 +32,7 @@
|
|
|
29
32
|
return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }).format(n)} ${units[i]}`;
|
|
30
33
|
}
|
|
31
34
|
const stamp = (value) => value ? new Date(value).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) : 'Date unavailable';
|
|
32
|
-
const mediaUrl = (file) => demoMode ? `assets/${file.asset}` : api.data.url(file.path);
|
|
35
|
+
const mediaUrl = (file) => demoMode && file.asset ? `assets/${file.asset}` : api.data.url(file.path);
|
|
33
36
|
function stopPlayback() {
|
|
34
37
|
previewRevision++;
|
|
35
38
|
for (const media of $('preview-media').querySelectorAll('video,audio')) { media.pause(); media.removeAttribute('src'); media.load(); }
|
|
@@ -37,30 +40,15 @@
|
|
|
37
40
|
}
|
|
38
41
|
function card(file) {
|
|
39
42
|
const li = document.createElement('li');
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const thumb = element('span', undefined, 'thumbnail');
|
|
43
|
-
thumb.append(icon(file.kind), element('span', labels[file.kind], 'fallback-label'));
|
|
44
|
-
if (file.kind === 'image' && model.browserImages.has(model.extension(file.path))) {
|
|
45
|
-
const image = document.createElement('img'); image.alt = ''; image.loading = 'lazy'; image.decoding = 'async';
|
|
46
|
-
image.addEventListener('error', () => { image.remove(); thumb.querySelector('.fallback-label').textContent = 'Preview unavailable'; });
|
|
47
|
-
try { image.src = mediaUrl(file); thumb.append(image); } catch { /* Keep the usable file card. */ }
|
|
48
|
-
}
|
|
49
|
-
const info = element('span', undefined, 'card-info');
|
|
50
|
-
info.append(element('span', file.path.split('/').pop(), 'file-name'), element('span', model.folderOf(file.path) === '.' ? 'Project folder' : model.folderOf(file.path), 'file-folder'), element('span', `${model.extension(file.path).toUpperCase()} · ${size(file.size)}`, 'file-meta'));
|
|
51
|
-
button.append(thumb, info); button.addEventListener('click', () => openPreview(file.path)); li.append(button); return li;
|
|
43
|
+
const card = components.fileCard(li, { file: { ...file, source: 'workspace' }, variant: view === 'list' ? 'row' : 'tile', thumbnail: file.kind === 'image' && model.browserImages.has(model.extension(file.path)) ? mediaUrl(file) : false, onActivate: () => openPreview(file.path) });
|
|
44
|
+
card.element.dataset.path = file.path; componentCards.push(card); return li;
|
|
52
45
|
}
|
|
53
46
|
function render() {
|
|
54
47
|
const previousFocus = document.activeElement?.dataset.path;
|
|
55
48
|
shown = model.select(files, { query: $('search').value, kind: $('kind').value, folder: $('folder').value, sort: $('sort').value });
|
|
56
49
|
$('gallery').dataset.view = view;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
$('gallery').replaceChildren(...shown.slice(0, visible).map((file) => {
|
|
60
|
-
const stamp = `${file.size}:${file.mtime}`;
|
|
61
|
-
if (cards.get(file.path)?.stamp !== stamp) cards.set(file.path, { stamp, node: card(file) });
|
|
62
|
-
return cards.get(file.path).node;
|
|
63
|
-
}));
|
|
50
|
+
componentCards.splice(0).forEach(card => card.destroy());
|
|
51
|
+
$('gallery').replaceChildren(...shown.slice(0, visible).map(card));
|
|
64
52
|
for (const type of ['image', 'video', 'audio']) $(`${type}-count`).textContent = files.filter((f) => f.kind === type).length.toLocaleString();
|
|
65
53
|
$('file-count').textContent = `${files.length.toLocaleString()} media file${files.length === 1 ? '' : 's'}`;
|
|
66
54
|
$('status').textContent = shown.length > visible ? `Showing ${visible} of ${shown.length.toLocaleString()} matches` : `${shown.length.toLocaleString()} of ${files.length.toLocaleString()} media files`;
|
|
@@ -68,7 +56,7 @@
|
|
|
68
56
|
$('no-matches').hidden = files.length === 0 || shown.length > 0;
|
|
69
57
|
$('show-more').hidden = shown.length <= visible;
|
|
70
58
|
$('view-grid').setAttribute('aria-pressed', String(view === 'grid')); $('view-list').setAttribute('aria-pressed', String(view === 'list'));
|
|
71
|
-
if (previousFocus) [...$('gallery').querySelectorAll('
|
|
59
|
+
if (previousFocus) [...$('gallery').querySelectorAll('gezel-file-card')].find((el) => el.dataset.path === previousFocus)?.shadowRoot.querySelector('button').focus();
|
|
72
60
|
}
|
|
73
61
|
function openPreview(path) {
|
|
74
62
|
const file = files.find((f) => f.path === path); if (!file) return;
|
|
@@ -115,7 +103,7 @@
|
|
|
115
103
|
if (busy) { again = true; return; } busy = true; $('refresh').disabled = true;
|
|
116
104
|
$('gallery').setAttribute('aria-busy', 'true'); message('error', '');
|
|
117
105
|
try {
|
|
118
|
-
const result = demoMode ? { files: samples, folders: ['.', 'Journeys', 'Studio', 'Motion', 'Recordings'] } : await model.scan((path) => api.data.list(path), { cancelled: () => stopped });
|
|
106
|
+
const result = demoMode ? { files: samples.concat(components.demo.files().map(file => ({ ...file, kind: model.kind(file.path) }))), folders: ['.', 'Journeys', 'Studio', 'Motion', 'Recordings'] } : await model.scan((path) => api.data.list(path), { cancelled: () => stopped });
|
|
119
107
|
if (stopped) return;
|
|
120
108
|
files = result.files;
|
|
121
109
|
const chosen = $('folder').value;
|
|
@@ -142,9 +130,9 @@
|
|
|
142
130
|
for (const style of ['grid', 'list']) $(`view-${style}`).addEventListener('click', () => { view = style; render(); });
|
|
143
131
|
$('show-more').addEventListener('click', () => { visible += 24; render(); });
|
|
144
132
|
$('refresh').addEventListener('click', () => { void refresh(); });
|
|
145
|
-
$('reset-demo').addEventListener('click', () => { $('search').value = ''; $('kind').value = ''; $('folder').value = ''; $('sort').value = 'newest'; visible = 24; view = 'grid'; $('preview').close(); void refresh(); });
|
|
133
|
+
$('reset-demo').addEventListener('click', () => { components.demo.reset(); adder.destroy(); adder = mountAdder(); $('search').value = ''; $('kind').value = ''; $('folder').value = ''; $('sort').value = 'newest'; visible = 24; view = 'grid'; $('preview').close(); void refresh(); });
|
|
146
134
|
$('close-preview').addEventListener('click', () => $('preview').close());
|
|
147
|
-
$('preview').addEventListener('close', () => { stopPlayback(); currentPath = null; [...$('gallery').querySelectorAll('
|
|
135
|
+
$('preview').addEventListener('close', () => { stopPlayback(); currentPath = null; [...$('gallery').querySelectorAll('gezel-file-card')].find((el) => el.dataset.path === focusPath)?.shadowRoot.querySelector('button').focus(); });
|
|
148
136
|
$('previous').addEventListener('click', () => move(-1)); $('next').addEventListener('click', () => move(1));
|
|
149
137
|
$('preview').addEventListener('keydown', (e) => {
|
|
150
138
|
if (['VIDEO', 'AUDIO', 'INPUT', 'SELECT'].includes(e.target.tagName)) return;
|
|
@@ -160,6 +148,6 @@
|
|
|
160
148
|
theme(api.ui.theme); const stopTheme = api.ui.onTheme(theme);
|
|
161
149
|
const timer = demoMode ? null : setInterval(() => { if (document.visibilityState !== 'hidden') void refresh(); }, 30000);
|
|
162
150
|
document.addEventListener('visibilitychange', () => { if (!demoMode && document.visibilityState !== 'hidden') schedule(); });
|
|
163
|
-
window.addEventListener('pagehide', () => { stopped = true; clearTimeout(debounce); clearInterval(timer); stopPlayback(); stopTheme(); for (const stop of watches.values()) stop(); }, { once: true });
|
|
151
|
+
window.addEventListener('pagehide', () => { stopped = true; adder.destroy(); componentCards.forEach(card => card.destroy()); clearTimeout(debounce); clearInterval(timer); stopPlayback(); stopTheme(); for (const stop of watches.values()) stop(); }, { once: true });
|
|
164
152
|
void refresh();
|
|
165
153
|
})();
|
|
@@ -6,101 +6,14 @@
|
|
|
6
6
|
<meta name="gezel-demo" content="standalone" />
|
|
7
7
|
<title>Media Library</title>
|
|
8
8
|
<link rel="stylesheet" href="gallery.css" />
|
|
9
|
-
|
|
10
|
-
/* gezel-page-demo-stub v1 */
|
|
11
|
-
/*
|
|
12
|
-
* The canonical demo stub for Gezel type pages. MIT License.
|
|
13
|
-
*
|
|
14
|
-
* Paste this file's bytes verbatim into a <script> block ahead of the
|
|
15
|
-
* page's own code, then call makeDemoGezel({ page, tools, data }) with the
|
|
16
|
-
* page's demo handlers. Served by Gezel, the real window.gezel is already
|
|
17
|
-
* injected and the stub steps aside; opened as a raw file (the live demos
|
|
18
|
-
* on gezelgilde.com), it installs a window.gezel whose tools and data are
|
|
19
|
-
* the page-supplied handler maps — one code path in every mode. `tools`
|
|
20
|
-
* and `data` map a tool name / declared read path to a function; data
|
|
21
|
-
* handlers back read() and list(), and url() returns the handler's value
|
|
22
|
-
* or passes a data: URI through. See docs/page-authoring.md.
|
|
23
|
-
*/
|
|
24
|
-
(function () {
|
|
25
|
-
'use strict';
|
|
26
|
-
window.makeDemoGezel = function (opts) {
|
|
27
|
-
if (window.gezel) return window.gezel;
|
|
28
|
-
var page = (opts && opts.page) || {};
|
|
29
|
-
var tools = (opts && opts.tools) || {};
|
|
30
|
-
var data = (opts && opts.data) || {};
|
|
31
|
-
var themeListeners = [];
|
|
32
|
-
var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
33
|
-
var ui = {
|
|
34
|
-
theme: { mode: media && media.matches ? 'dark' : 'light' },
|
|
35
|
-
onTheme: function (cb) {
|
|
36
|
-
themeListeners.push(cb);
|
|
37
|
-
return function () {
|
|
38
|
-
var at = themeListeners.indexOf(cb);
|
|
39
|
-
if (at >= 0) themeListeners.splice(at, 1);
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
if (media && media.addEventListener) {
|
|
44
|
-
media.addEventListener('change', function (ev) {
|
|
45
|
-
ui.theme = { mode: ev.matches ? 'dark' : 'light' };
|
|
46
|
-
themeListeners.slice().forEach(function (cb) { cb(ui.theme); });
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
function fail(code, message) {
|
|
50
|
-
var err = new Error(message);
|
|
51
|
-
err.code = code;
|
|
52
|
-
return Promise.reject(err);
|
|
53
|
-
}
|
|
54
|
-
function run(map, key, arg) {
|
|
55
|
-
if (!Object.prototype.hasOwnProperty.call(map, key)) return null;
|
|
56
|
-
return Promise.resolve().then(function () { return map[key](arg); });
|
|
57
|
-
}
|
|
58
|
-
window.gezel = {
|
|
59
|
-
page: {
|
|
60
|
-
api: 1,
|
|
61
|
-
projectId: 'demo',
|
|
62
|
-
source: 'type',
|
|
63
|
-
entry: page.entry || 'index.html',
|
|
64
|
-
typeName: page.typeName || 'demo',
|
|
65
|
-
params: page.params || {},
|
|
66
|
-
mode: 'demo',
|
|
67
|
-
},
|
|
68
|
-
tools: {
|
|
69
|
-
list: function () { return Promise.resolve(Object.keys(tools)); },
|
|
70
|
-
invoke: function (name, input) {
|
|
71
|
-
var call = run(tools, name, input || {});
|
|
72
|
-
if (!call) return fail('not-allowed', "The demo does not handle the tool '" + name + "'.");
|
|
73
|
-
return call.then(function (output) { return { output: output }; });
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
data: {
|
|
77
|
-
read: function (path, o) {
|
|
78
|
-
return run(data, path, o || {}) || fail('not-allowed', "The demo has no data for '" + path + "'.");
|
|
79
|
-
},
|
|
80
|
-
list: function (path, o) {
|
|
81
|
-
return run(data, path, o || {}) || Promise.resolve([]);
|
|
82
|
-
},
|
|
83
|
-
watch: function () { return function () {}; },
|
|
84
|
-
url: function (path) {
|
|
85
|
-
if (Object.prototype.hasOwnProperty.call(data, path)) return String(data[path]({}));
|
|
86
|
-
return typeof path === 'string' && path.indexOf('data:') === 0 ? path : '';
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
ui: ui,
|
|
90
|
-
refresh: function () {},
|
|
91
|
-
};
|
|
92
|
-
return window.gezel;
|
|
93
|
-
};
|
|
94
|
-
})();
|
|
95
|
-
|
|
96
|
-
</script>
|
|
97
|
-
<script src="media-files.js" defer></script>
|
|
9
|
+
<script src="media-files.js" defer></script>
|
|
98
10
|
<script src="gallery.js" defer></script>
|
|
99
11
|
</head>
|
|
100
12
|
<body>
|
|
101
13
|
<main>
|
|
102
14
|
<aside data-gezel-demo-banner hidden><span>Sample library. Illustrations, a short clip, and three notes — all local to this page.</span><button id="reset-demo" type="button">Reset demo</button></aside>
|
|
103
15
|
<header><div><p class="eyebrow">Your collection, in place</p><h1>Media Library</h1><p class="intro">A window into your photos, films, and recordings.</p></div><button id="refresh" type="button">Refresh</button></header>
|
|
16
|
+
<div id="add-files"></div>
|
|
104
17
|
<dl class="counts" aria-label="Library summary"><div><dt>Images</dt><dd id="image-count">—</dd></div><div><dt>Videos</dt><dd id="video-count">—</dd></div><div><dt>Audio</dt><dd id="audio-count">—</dd></div></dl>
|
|
105
18
|
<section aria-labelledby="library-heading">
|
|
106
19
|
<div class="library-heading"><h2 id="library-heading">Browse your library</h2><span id="updated"></span></div>
|
|
@@ -117,7 +30,7 @@
|
|
|
117
30
|
<div id="empty" class="empty" hidden><h2>Your library starts here</h2><p>Choose a media folder when creating this project, or set its folder in project settings. Images, videos, and audio in that folder and its subfolders appear automatically.</p></div>
|
|
118
31
|
<p id="no-matches" class="empty" hidden>No media matches these filters. Try another name, folder, or media type.</p>
|
|
119
32
|
</section>
|
|
120
|
-
<footer><span id="file-count"></span> · Originals stay in your folder.
|
|
33
|
+
<footer><span id="file-count"></span> · Originals stay in your folder. Add files copies selected files into this folder. Playback depends on the formats supported by your device.</footer>
|
|
121
34
|
</main>
|
|
122
35
|
<dialog id="preview" aria-labelledby="preview-title">
|
|
123
36
|
<div class="preview-heading"><div><h2 id="preview-title"></h2><p id="preview-path" class="muted"></p></div><button id="close-preview" type="button" autofocus>Close</button></div>
|