ui(badges): add background image bleed support (cfg_json, PVC layout)
- Add `bleed` field to BadgeTemplateCfg (CSS length, e.g. "0.125in") - Badge view: derive bleed_offset, move bg-image to absolute positioned div that extends past card edges; add isolation:isolate to badge_front stacking context - Template form: add bleed input in Advanced > Appearance; wire to cfg_json save/load - PVC layout CSS: change overflow:hidden → overflow:visible in print rule to allow bleed div to render at physical card boundary (Zebra driver clips at card edge) - Prevents white borders on PVC cards when printer has slight alignment variance. Screen preview shows bleed visually extending past the card outline.
This commit is contained in:
@@ -44,6 +44,8 @@
|
|||||||
height: 5.5in !important;
|
height: 5.5in !important;
|
||||||
max-width: 3.5in !important;
|
max-width: 3.5in !important;
|
||||||
max-height: 5.5in !important;
|
max-height: 5.5in !important;
|
||||||
overflow: hidden !important;
|
/* Allow visible: the bleed div inside badge_front extends past the card
|
||||||
|
boundary intentionally. The Zebra driver clips at the physical card edge. */
|
||||||
|
overflow: visible !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ export interface BadgeTemplateCfg {
|
|||||||
// Body text color: either a Tailwind `text-*` class or a hex color like `#112233`.
|
// Body text color: either a Tailwind `text-*` class or a hex color like `#112233`.
|
||||||
body_text_color?: string;
|
body_text_color?: string;
|
||||||
|
|
||||||
|
// Background image bleed: how far the background image extends past the physical
|
||||||
|
// card edge on all four sides. Prevents white borders when the printer clips at the
|
||||||
|
// card boundary. Any CSS length is valid: "0.125in", "3mm", "9px".
|
||||||
|
// Leave unset (or "0") for no bleed.
|
||||||
|
bleed?: string;
|
||||||
|
|
||||||
// Allow arbitrary extra keys to preserve forward-compatibility.
|
// Allow arbitrary extra keys to preserve forward-compatibility.
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,6 +309,15 @@ let body_text_color_style = $derived.by(() => {
|
|||||||
return 'color: #000000;';
|
return 'color: #000000;';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Background image bleed: template cfg_json.bleed is a CSS length like "0.125in" or "3mm".
|
||||||
|
// We negate it here so it can be used as a CSS inset value on the bleed container div.
|
||||||
|
// "0px" means no bleed — the bg image is flush with the badge edges (same as before).
|
||||||
|
let bleed_offset = $derived.by(() => {
|
||||||
|
const b = template_cfg?.bleed;
|
||||||
|
if (!b || b === '0' || b === '0px') return '0px';
|
||||||
|
return `-${b}`;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout-aware section heights for Element_fit_text.
|
* Layout-aware section heights for Element_fit_text.
|
||||||
*
|
*
|
||||||
@@ -615,9 +624,7 @@ const code_to_icon: {
|
|||||||
text-center hover:outline-2 hover:outline-red-500/75
|
text-center hover:outline-2 hover:outline-red-500/75
|
||||||
hover:outline-dashed
|
hover:outline-dashed
|
||||||
"
|
"
|
||||||
style="{bg_image_path
|
style="isolation: isolate;{demo_bg_style ? ` ${demo_bg_style}` : ''}">
|
||||||
? `background-image: url('${bg_image_path}'); background-size: cover; background-position: top center; background-repeat: no-repeat;`
|
|
||||||
: ''}{demo_bg_style ? ` ${demo_bg_style}` : ''}">
|
|
||||||
<span
|
<span
|
||||||
class="
|
class="
|
||||||
absolute top-1 left-4 text-xs
|
absolute top-1 left-4 text-xs
|
||||||
@@ -628,6 +635,20 @@ const code_to_icon: {
|
|||||||
{#if show_badge_back}Front of badge{:else}Badge preview{/if}
|
{#if show_badge_back}Front of badge{:else}Badge preview{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<!-- Background image bleed container.
|
||||||
|
Absolutely positioned so it can extend past badge_front's edges by bleed_offset
|
||||||
|
(e.g. "-0.125in" on all sides). z-index: -1 keeps it behind all badge content.
|
||||||
|
badge_front has isolation: isolate so the negative z-index stays within its
|
||||||
|
stacking context and doesn't punch through parent backgrounds.
|
||||||
|
When bleed_offset is "0px" this is flush with the badge edges (same as before). -->
|
||||||
|
{#if bg_image_path}
|
||||||
|
<div
|
||||||
|
class="pointer-events-none absolute"
|
||||||
|
aria-hidden="true"
|
||||||
|
style="top: {bleed_offset}; right: {bleed_offset}; bottom: {bleed_offset}; left: {bleed_offset}; z-index: -1; background-image: url('{bg_image_path}'); background-size: cover; background-position: top center; background-repeat: no-repeat;">
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Header: controlled by per-template cfg_json (hide_badge_header).
|
<!-- Header: controlled by per-template cfg_json (hide_badge_header).
|
||||||
If cfg.hide_badge_header is set, it overrides the default. By default
|
If cfg.hide_badge_header is set, it overrides the default. By default
|
||||||
a background image will hide the header unless explicitly overridden. -->
|
a background image will hide the header unless explicitly overridden. -->
|
||||||
@@ -1310,7 +1331,7 @@ const code_to_icon: {
|
|||||||
}
|
}
|
||||||
.name_pad_long {
|
.name_pad_long {
|
||||||
/* padding-left: 2%; */
|
/* padding-left: 2%; */
|
||||||
/* padding-right: 0%; */
|
padding-right: 0%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ let cfg_controls_shown: string[] = $state(['name', 'title', 'affiliations', 'loc
|
|||||||
let cfg_controls_auth_editable: string[] = $state([]);
|
let cfg_controls_auth_editable: string[] = $state([]);
|
||||||
// Body text color (hex)
|
// Body text color (hex)
|
||||||
let cfg_body_text_color = $state('#000000');
|
let cfg_body_text_color = $state('#000000');
|
||||||
|
// Background image bleed (CSS length, e.g. "0.125in", "3mm"). Empty = no bleed.
|
||||||
|
let cfg_bleed = $state('');
|
||||||
// Alignment overrides: 'left' | 'center' | 'right' | 'justify'
|
// Alignment overrides: 'left' | 'center' | 'right' | 'justify'
|
||||||
let cfg_align_name = $state('center');
|
let cfg_align_name = $state('center');
|
||||||
let cfg_align_title = $state('center');
|
let cfg_align_title = $state('center');
|
||||||
@@ -156,6 +158,9 @@ async function load_template(id: string) {
|
|||||||
cfg_body_text_color = '#000000';
|
cfg_body_text_color = '#000000';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background bleed (CSS length, e.g. "0.125in"). Empty = no bleed.
|
||||||
|
cfg_bleed = parsed_cfg.bleed ?? '';
|
||||||
|
|
||||||
// Alignment overrides (nested under cfg_json.align and cfg_json.qr_alignment)
|
// Alignment overrides (nested under cfg_json.align and cfg_json.qr_alignment)
|
||||||
cfg_align_name = parsed_cfg?.align?.name ?? parsed_cfg.align_name ?? 'center';
|
cfg_align_name = parsed_cfg?.align?.name ?? parsed_cfg.align_name ?? 'center';
|
||||||
cfg_align_title = parsed_cfg?.align?.title ?? parsed_cfg.align_title ?? 'center';
|
cfg_align_title = parsed_cfg?.align?.title ?? parsed_cfg.align_title ?? 'center';
|
||||||
@@ -226,6 +231,13 @@ async function handle_submit() {
|
|||||||
if ((cfg_obj as any)?.body_text_color_hex) delete (cfg_obj as any).body_text_color_hex;
|
if ((cfg_obj as any)?.body_text_color_hex) delete (cfg_obj as any).body_text_color_hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background bleed: save if set, remove key entirely when cleared
|
||||||
|
if (cfg_bleed.trim()) {
|
||||||
|
cfg_obj.bleed = cfg_bleed.trim();
|
||||||
|
} else {
|
||||||
|
delete cfg_obj.bleed;
|
||||||
|
}
|
||||||
|
|
||||||
const data_to_save: key_val = {
|
const data_to_save: key_val = {
|
||||||
name,
|
name,
|
||||||
background_image_path,
|
background_image_path,
|
||||||
@@ -525,6 +537,15 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
|||||||
Pick a hex color (e.g. #112233). The renderer will use this inline color.
|
Pick a hex color (e.g. #112233). The renderer will use this inline color.
|
||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="label mt-3">
|
||||||
|
<span>Background Image Bleed</span>
|
||||||
|
<input type="text" bind:value={cfg_bleed} class="input" placeholder="e.g. 0.125in or 3mm" />
|
||||||
|
<p class="text-xs text-surface-400 italic">
|
||||||
|
Extends the background image past the card edge on all four sides — prevents a white border
|
||||||
|
if the printer clips slightly inside the physical card boundary. Any CSS length works
|
||||||
|
(<code>0.125in</code>, <code>3mm</code>, <code>9px</code>). Leave blank for no bleed.
|
||||||
|
</p>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-t pt-2">
|
<div class="border-t pt-2">
|
||||||
<h4 class="font-semibold">Controls Menu Toggles</h4>
|
<h4 class="font-semibold">Controls Menu Toggles</h4>
|
||||||
|
|||||||
Reference in New Issue
Block a user