Skip to content

Commit 93a88e4

Browse files
committed
added date picker
1 parent a0335b8 commit 93a88e4

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

js/app.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@
6767
// Image layers driven by a dropdown (e.g. the project logo).
6868
const selectLayers = []; // {field, label, options, el}
6969

70+
// One date picker can drive multiple text fields (see datePart in templates.js).
71+
let datePicker = null; // {label, default}
72+
73+
// Parse a YYYY-MM-DD value as a LOCAL date (avoids UTC-shift to the previous day).
74+
function parseLocalDate(value) {
75+
const [y, m, d] = value.split('-').map(Number);
76+
return new Date(y, m - 1, d);
77+
}
78+
const DATE_PARTS = {
79+
weekday: (dt) => dt.toLocaleDateString('en-US', { weekday: 'long' }) + ',',
80+
monthday: (dt) => dt.toLocaleDateString('en-US', { month: 'long', day: 'numeric' }),
81+
};
82+
function formatDatePart(value, part) {
83+
const fn = DATE_PARTS[part];
84+
return fn ? fn(parseLocalDate(value)) : value;
85+
}
86+
7087
function makeImage(layer) {
7188
const img = document.createElement('img');
7289
img.className = 'layer-image';
@@ -92,7 +109,7 @@
92109
applyFont(span, Object.assign({}, parentFont, child.font), parentColor, parentTitleCase);
93110
if (child.editable) {
94111
span.dataset.field = child.field;
95-
fields.push({ field: child.field, label: child.label, default: child.default, el: span });
112+
fields.push({ field: child.field, label: child.label, default: child.default, el: span, datePart: child.datePart });
96113
}
97114
return span;
98115
}
@@ -149,7 +166,9 @@
149166
optionalLayers.length = 0;
150167
shiftEls.length = 0;
151168
selectLayers.length = 0;
169+
datePicker = null;
152170
for (const layer of tpl.layers) {
171+
if (layer.datePicker) datePicker = layer.datePicker;
153172
const el = buildLayer(layer);
154173
if (layer.shiftOnCollapse) shiftEls.push(el);
155174
if (layer.optional) {
@@ -206,13 +225,40 @@
206225
return wrap;
207226
}
208227

228+
function makeDatePicker(spec, dateFields) {
229+
const wrap = document.createElement('label');
230+
wrap.className = 'field';
231+
const span = document.createElement('span');
232+
span.className = 'field-label';
233+
span.textContent = spec.label;
234+
const input = document.createElement('input');
235+
input.type = 'date';
236+
input.value = spec.default || '';
237+
const apply = () => {
238+
if (!input.value) return;
239+
for (const f of dateFields) f.el.textContent = formatDatePart(input.value, f.datePart);
240+
};
241+
input.addEventListener('input', apply);
242+
apply(); // sync spans to the initial date
243+
wrap.appendChild(span);
244+
wrap.appendChild(input);
245+
return wrap;
246+
}
247+
209248
function buildControls() {
210249
controlsEl.innerHTML = '';
211250
// Dropdowns first (e.g. project logo).
212251
for (const sel of selectLayers) controlsEl.appendChild(makeSelect(sel));
213252

253+
// One date picker drives all date-derived fields (Weekday + Date).
254+
const dateFields = fields.filter((f) => f.datePart);
255+
if (datePicker && dateFields.length) {
256+
controlsEl.appendChild(makeDatePicker(datePicker, dateFields));
257+
}
258+
214259
const emittedToggles = new Set();
215260
for (const f of fields) {
261+
if (f.datePart) continue; // handled by the date picker
216262
const opt = optionalLayerForField(f.field);
217263
if (opt && !emittedToggles.has(opt)) {
218264
emittedToggles.add(opt);

js/templates.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ window.TEMPLATES = [
7373
font: { weight: 400, size: 38, lineHeight: 33.44, letterSpacing: -0.38 },
7474
color: INK,
7575
titleCase: true,
76+
// Weekday + Date are driven by one date picker (see datePart below).
77+
datePicker: { label: 'Event date', default: '2026-05-27' },
7678
children: [
77-
{ kind: 'text', editable: true, field: 'weekday', label: 'Weekday', default: 'Wednesday,' },
78-
{ kind: 'text', editable: true, field: 'date', label: 'Date', default: 'May 27', font: { weight: 700 } },
79+
{ kind: 'text', editable: true, field: 'weekday', label: 'Weekday', default: 'Wednesday,', datePart: 'weekday' },
80+
{ kind: 'text', editable: true, field: 'date', label: 'Date', default: 'May 27', font: { weight: 700 }, datePart: 'monthday' },
7981
{ kind: 'text', text: '|' },
8082
{ kind: 'text', editable: true, field: 'city', label: 'City', default: 'Rome' },
8183
],

0 commit comments

Comments
 (0)