Replace QR code with barcode on labels, centre all text
Deploy to LXC / deploy (push) Successful in 31s
Deploy to LXC / deploy (push) Successful in 31s
All print labels (device, component, batch) now show centred text with a Code 128 barcode at the bottom instead of a QR code on the left. Layout uses vertical flex column for clean centring. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { db } from '$lib/server/db/index.js';
|
|||||||
import { devices } from '$lib/server/db/schema.js';
|
import { devices } from '$lib/server/db/schema.js';
|
||||||
import { sql } from 'drizzle-orm';
|
import { sql } from 'drizzle-orm';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import { generateQrSvg } from '$lib/server/qr.js';
|
import { generateBarcodeSvg } from '$lib/server/barcode.js';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ url }) => {
|
export const load: PageServerLoad = async ({ url }) => {
|
||||||
const idsParam = url.searchParams.get('ids');
|
const idsParam = url.searchParams.get('ids');
|
||||||
@@ -26,12 +26,11 @@ export const load: PageServerLoad = async ({ url }) => {
|
|||||||
.from(devices)
|
.from(devices)
|
||||||
.where(sql`${devices.id} IN ${ids}`);
|
.where(sql`${devices.id} IN ${ids}`);
|
||||||
|
|
||||||
// Generate QR codes for each
|
|
||||||
const labels = await Promise.all(
|
const labels = await Promise.all(
|
||||||
deviceList.map(async (device) => {
|
deviceList.map(async (device) => {
|
||||||
const shortId = device.id.slice(0, 8).toUpperCase();
|
const shortId = device.id.slice(0, 8).toUpperCase();
|
||||||
const qrSvg = await generateQrSvg(shortId);
|
const barcodeDataUrl = await generateBarcodeSvg(shortId);
|
||||||
return { ...device, qrSvg, shortId };
|
return { ...device, barcodeDataUrl, shortId };
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -32,30 +32,25 @@
|
|||||||
|
|
||||||
{#each data.labels as label}
|
{#each data.labels as label}
|
||||||
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
||||||
<div style="display: flex; align-items: center; gap: 2mm; height: 100%; font-family: 'JetBrains Mono', monospace;">
|
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; font-family: 'JetBrains Mono', monospace; text-align: center;">
|
||||||
<div style="width: 22mm; height: 22mm; flex-shrink: 0;">
|
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
{@html label.qrSvg}
|
{label.title}
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1; min-width: 0; text-align: center;">
|
{#if label.brand || label.model}
|
||||||
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
<div style="font-size: 5.5pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
{label.title}
|
{[label.brand, label.model].filter(Boolean).join(' ')}
|
||||||
</div>
|
</div>
|
||||||
{#if label.brand || label.model}
|
{/if}
|
||||||
<div style="font-size: 5.5pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
{#if label.serialNumber}
|
||||||
{[label.brand, label.model].filter(Boolean).join(' ')}
|
<div style="font-size: 5pt; color: #666;">S/N: {label.serialNumber}</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{#if label.voltage || label.frequency}
|
||||||
{#if label.serialNumber}
|
<div style="font-size: 5pt; color: #666;">
|
||||||
<div style="font-size: 5pt; color: #666;">S/N: {label.serialNumber}</div>
|
{[label.voltage, label.frequency].filter(Boolean).join(' / ')}
|
||||||
{/if}
|
|
||||||
{#if label.voltage || label.frequency}
|
|
||||||
<div style="font-size: 5pt; color: #666;">
|
|
||||||
{[label.voltage, label.frequency].filter(Boolean).join(' / ')}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div style="font-size: 11pt; font-weight: bold; color: #000; margin-top: 0.5mm; letter-spacing: 1px;">
|
|
||||||
{label.shortId}
|
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div style="margin-top: 0.5mm;">
|
||||||
|
<img src={label.barcodeDataUrl} alt={label.shortId} style="height: 8mm; width: auto; max-width: 58mm;" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { db } from '$lib/server/db/index.js';
|
|||||||
import { components } from '$lib/server/db/schema.js';
|
import { components } from '$lib/server/db/schema.js';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import { generateQrSvg } from '$lib/server/qr.js';
|
import { generateBarcodeSvg } from '$lib/server/barcode.js';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ params }) => {
|
export const load: PageServerLoad = async ({ params }) => {
|
||||||
const [component] = await db
|
const [component] = await db
|
||||||
@@ -20,7 +20,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
|||||||
if (!component) error(404, 'Component not found');
|
if (!component) error(404, 'Component not found');
|
||||||
|
|
||||||
const shortId = component.id.slice(0, 8).toUpperCase();
|
const shortId = component.id.slice(0, 8).toUpperCase();
|
||||||
const qrSvg = await generateQrSvg(shortId);
|
const barcodeDataUrl = await generateBarcodeSvg(shortId);
|
||||||
|
|
||||||
return { component, qrSvg, shortId };
|
return { component, barcodeDataUrl, shortId };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,26 +40,19 @@
|
|||||||
|
|
||||||
{#each Array(copies) as _}
|
{#each Array(copies) as _}
|
||||||
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
||||||
<div style="display: flex; align-items: center; gap: 2mm; height: 100%; font-family: 'JetBrains Mono', monospace;">
|
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; font-family: 'JetBrains Mono', monospace; text-align: center;">
|
||||||
<div style="width: 22mm; height: 22mm; flex-shrink: 0;">
|
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
{@html data.qrSvg}
|
{data.component.title}
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1; min-width: 0; text-align: center;">
|
<div style="font-size: 5.5pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
{data.component.componentType}
|
||||||
{data.component.title}
|
{#if data.component.brand}· {data.component.brand}{/if}
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 6pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
{#if data.component.partNumber}
|
||||||
{data.component.componentType}
|
<div style="font-size: 5pt; color: #666;">P/N: {data.component.partNumber}</div>
|
||||||
{#if data.component.brand}· {data.component.brand}{/if}
|
{/if}
|
||||||
</div>
|
<div style="margin-top: 0.5mm;">
|
||||||
{#if data.component.partNumber}
|
<img src={data.barcodeDataUrl} alt={data.shortId} style="height: 8mm; width: auto; max-width: 58mm;" />
|
||||||
<div style="font-size: 6pt; color: #666; margin-top: 0.3mm;">
|
|
||||||
P/N: {data.component.partNumber}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div style="font-size: 11pt; font-weight: bold; color: #000; margin-top: 0.5mm; letter-spacing: 1px;">
|
|
||||||
{data.shortId}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { db } from '$lib/server/db/index.js';
|
|||||||
import { devices } from '$lib/server/db/schema.js';
|
import { devices } from '$lib/server/db/schema.js';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import { generateQrSvg } from '$lib/server/qr.js';
|
import { generateBarcodeSvg } from '$lib/server/barcode.js';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ params }) => {
|
export const load: PageServerLoad = async ({ params }) => {
|
||||||
const [device] = await db
|
const [device] = await db
|
||||||
@@ -23,7 +23,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
|||||||
if (!device) error(404, 'Device not found');
|
if (!device) error(404, 'Device not found');
|
||||||
|
|
||||||
const shortId = device.id.slice(0, 8).toUpperCase();
|
const shortId = device.id.slice(0, 8).toUpperCase();
|
||||||
const qrSvg = await generateQrSvg(shortId);
|
const barcodeDataUrl = await generateBarcodeSvg(shortId);
|
||||||
|
|
||||||
return { device, qrSvg, shortId };
|
return { device, barcodeDataUrl, shortId };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,30 +40,25 @@
|
|||||||
|
|
||||||
{#each Array(copies) as _}
|
{#each Array(copies) as _}
|
||||||
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
<div class="label" style="width: 62mm; height: 29mm; background: white; color: black; box-sizing: border-box; padding: 1mm; margin: 0 auto 8px auto; border: 1px dashed #ccc; overflow: hidden;">
|
||||||
<div style="display: flex; align-items: center; gap: 2mm; height: 100%; font-family: 'JetBrains Mono', monospace;">
|
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; font-family: 'JetBrains Mono', monospace; text-align: center;">
|
||||||
<div style="width: 22mm; height: 22mm; flex-shrink: 0;">
|
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
{@html data.qrSvg}
|
{data.device.title}
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1; min-width: 0; text-align: center;">
|
{#if data.device.brand || data.device.model}
|
||||||
<div style="font-size: 9pt; font-weight: bold; color: #000; line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
<div style="font-size: 5.5pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;">
|
||||||
{data.device.title}
|
{[data.device.brand, data.device.model].filter(Boolean).join(' ')}
|
||||||
</div>
|
</div>
|
||||||
{#if data.device.brand || data.device.model}
|
{/if}
|
||||||
<div style="font-size: 5.5pt; color: #444; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
{#if data.device.serialNumber}
|
||||||
{[data.device.brand, data.device.model].filter(Boolean).join(' ')}
|
<div style="font-size: 5pt; color: #666;">S/N: {data.device.serialNumber}</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{#if data.device.voltage || data.device.frequency}
|
||||||
{#if data.device.serialNumber}
|
<div style="font-size: 5pt; color: #666;">
|
||||||
<div style="font-size: 5pt; color: #666;">S/N: {data.device.serialNumber}</div>
|
{[data.device.voltage, data.device.frequency].filter(Boolean).join(' / ')}
|
||||||
{/if}
|
|
||||||
{#if data.device.voltage || data.device.frequency}
|
|
||||||
<div style="font-size: 5pt; color: #666;">
|
|
||||||
{[data.device.voltage, data.device.frequency].filter(Boolean).join(' / ')}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div style="font-size: 11pt; font-weight: bold; color: #000; margin-top: 0.5mm; letter-spacing: 1px;">
|
|
||||||
{data.shortId}
|
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div style="margin-top: 0.5mm;">
|
||||||
|
<img src={data.barcodeDataUrl} alt={data.shortId} style="height: 8mm; width: auto; max-width: 58mm;" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user