diff --git a/app/templates/admin/labels/tape.html b/app/templates/admin/labels/tape.html index 8ee54d8..4cc8621 100644 --- a/app/templates/admin/labels/tape.html +++ b/app/templates/admin/labels/tape.html @@ -18,6 +18,9 @@ opened with no options at all. Without it, a default-on checkbox could never be turned off. #} +{# Which parts share a physical label: "1,2|3". Rewritten by the Combine + and Split buttons under the preview. Empty means "group by drawer". #} +
@@ -67,9 +70,29 @@ value="{{ options.copies }}">
- - + + +
+
+ +
+ {% for preset, text in [(1.0, 'Normal'), (1.5, 'Large'), (2.0, 'Huge'), (3.0, 'Max')] %} + + {% endfor %} +
+
+ The part name is sized first and the image gives way to + it, so turning this up shrinks the picture rather than + clipping the text. The whole name always prints - it wraps + and settles at the largest size that fits, so a long name + stops growing before a short one does. Untick + Part image for the biggest type of all. +
@@ -161,6 +184,13 @@ Download PDF
+
+ Jobs are sent one at a time: LIM waits for the printer to + finish each label before sending the next, because the + VC-500W answers "busy" to anything that arrives mid-print. + So a big run takes a while - leave the page alone until it + comes back rather than refreshing, or you'll print twice. +
{% else %}

@@ -195,9 +225,32 @@ will be scaled down. Load 50mm tape, or pick a different size. {% endif %} +

+ Tick labels, then: + + + +
+
+ For customs and MOC drawers, where the parts have no drawer in + common. A combined label grows 5mm for each part past the second, + and hand-made groups are kept whatever the size setting says. +
+
{% for item in plan[:12] %} -
+
+ {{ item.labels | map(attribute='display_title') | join(' + ') }} Printing…'; + } +}); + document.getElementById('testBtn')?.addEventListener('click', function () { const out = document.getElementById('testResult'); out.innerHTML = 'Probing…'; @@ -283,5 +347,102 @@ document.getElementById('testBtn')?.addEventListener('click', function () { document.getElementById(id)?.addEventListener('change', () => document.getElementById('tapeForm').submit()); }); + +// Text size: slider, box and presets all drive the one value. +(function () { + const num = document.getElementById('fontNum'); + const range = document.getElementById('fontRange'); + const out = document.getElementById('fontOut'); + if (!num || !range) { return; } + const show = v => { if (out) { out.textContent = Number(v).toFixed(2) + '×'; } }; + num.addEventListener('input', () => { range.value = num.value; show(num.value); }); + range.addEventListener('input', () => { num.value = range.value; show(range.value); }); + range.addEventListener('change', () => document.getElementById('tapeForm').submit()); + document.querySelectorAll('.font-preset').forEach(btn => { + btn.addEventListener('click', () => { + num.value = range.value = btn.dataset.scale; + show(btn.dataset.scale); + document.getElementById('tapeForm').submit(); + }); + }); +})(); + +// Combining parts onto one label by hand. +// +// The grouping lives in the hidden `groups` field as "1,2|3". These buttons +// rewrite it from what is ticked and resubmit, so the preview always shows +// the real physical labels rather than a guess. +// +// The starting point is the whole current plan (data-plan), not just the +// cards on screen - only the first 12 labels are previewed, and a spec built +// from those alone would quietly un-group everything after them. +(function () { + const spec = document.getElementById('groupSpec'); + const bar = document.getElementById('groupBar'); + const form = document.getElementById('tapeForm'); + if (!spec || !bar || !form) { return; } + + const plan = () => (bar.dataset.plan || '') + .split('|').filter(Boolean).map(g => g.split(',').filter(Boolean)); + + function tickedIds() { + const ids = new Set(); + document.querySelectorAll('.plan-card').forEach(card => { + if (card.querySelector('.plan-pick')?.checked) { + (card.dataset.ids || '').split(',').filter(Boolean) + .forEach(id => ids.add(id)); + } + }); + return ids; + } + + function write(groups) { + spec.value = groups.filter(g => g.length).map(g => g.join(',')).join('|'); + form.submit(); + } + + document.getElementById('combineBtn')?.addEventListener('click', () => { + const picked = tickedIds(); + if (picked.size < 2) { + alert('Tick two or more labels to combine them onto one.'); + return; + } + const groups = []; + const merged = []; + let placed = false; + plan().forEach(group => { + const mine = group.filter(id => picked.has(id)); + const rest = group.filter(id => !picked.has(id)); + if (mine.length) { + merged.push(...mine); + // Keep the combined label where the first ticked part was, + // so the preview does not jump to the end of a long list. + if (!placed) { groups.push(merged); placed = true; } + } + if (rest.length) { groups.push(rest); } + }); + write(groups); + }); + + document.getElementById('splitBtn')?.addEventListener('click', () => { + const picked = tickedIds(); + if (!picked.size) { + alert('Tick the labels you want split apart first.'); + return; + } + const groups = []; + plan().forEach(group => { + const rest = group.filter(id => !picked.has(id)); + group.filter(id => picked.has(id)).forEach(id => groups.push([id])); + if (rest.length) { groups.push(rest); } + }); + write(groups); + }); + + document.getElementById('resetGroupsBtn')?.addEventListener('click', () => { + spec.value = ''; + form.submit(); + }); +})(); {% endblock %}