(int)round($c + ($target - $c) * $amount), $p)); } /** * The colour of a ticket category on the ticket. The colour set on the category wins. Without one, the name decides * (Gold is gold, Silver is silver, and so on) and every other category gets its own colour in the order the * categories are listed, so two categories of one event never look alike. */ function ticket_category_color(int $eventId, int $categoryId, string $name, ?string $explicit): string { if ($explicit && preg_match('/^#[0-9a-f]{6}$/i', $explicit)) return strtolower($explicit); $n = strtolower($name); foreach (['platinum' => '#4b5563', 'gold' => '#b8860b', 'silver' => '#8b939c', 'bronze' => '#a0522d', 'vip' => '#6d28d9', 'premium' => '#6d28d9', 'early' => '#0d9488', 'student' => '#15803d', 'staff' => '#0f172a', 'crew' => '#0f172a', 'press' => '#0f172a'] as $word => $hex) { if (str_contains($n, $word)) return $hex; } $ids = array_map('intval', array_column(q('SELECT id FROM {ticket_categories} WHERE event_id = ? ORDER BY sort_order, id', [$eventId])->fetchAll(), 'id')); $i = max(0, (int)array_search($categoryId, $ids, true)); $cycle = ['#1d4ed8', '#c2410c', '#0f766e', '#be185d', '#4d7c0f', '#b91c1c', '#0369a1']; return $cycle[$i % count($cycle)]; } /** The category colour of one ticket (its own colour, or the one chosen by name or position). */ function ticket_color(array $ev, array $t): string { static $own = []; $cid = (int)$t['category_id']; if (!array_key_exists($cid, $own)) $own[$cid] = qv('SELECT color FROM {ticket_categories} WHERE id = ?', [$cid]); return ticket_category_color((int)$ev['id'], $cid, (string)$t['category_name'], $own[$cid] ? (string)$own[$cid] : null); } /** The gate as a quiet single-colour watermark. Pure vector with no filters, so it stays sharp when saved as a PDF. */ function gate_watermark_svg(string $class = 'tk-wm'): string { $out = ''; } /** * Everything the ticket card needs that is the same for every ticket in a booking. Used by the PDF sheet and by the * booking page, so both show the same ticket. 'css' holds the colour rules, to print inside a style tag. */ function ticket_card_ctx(array $o, array $ev, array $tickets): array { $brand = brand_color(); $on = brand_on_color(); $dark = max(array_map('hexdec', str_split(substr($brand, 1), 2))) < 48 ? '#1f4b5e' : brand_shade(0.62); // near-black brands (the Gatecraft default) pair with the brand teal $logo = upload_url(setting('brand_logo_dark') ?: setting('brand_logo')); $cover = upload_url($ev['cover_image'] ?? ''); $brandName = setting('brand_name'); $place = array_filter([$ev['venue_name'], $ev['venue_address'], trim(($ev['venue_postal'] ?? '') . ' ' . ($ev['venue_city'] ?? ''))]); $times = array_filter([$ev['doors_at'] ? 'Doors ' . fmt_time($ev['doors_at']) : '', 'Starts ' . fmt_time($ev['starts_at']), $ev['ends_at'] ? 'Ends ' . fmt_time($ev['ends_at']) : '']); $cats = []; foreach ($tickets as $t) { $hex = ticket_color($ev, $t); $key = substr($hex, 1); if (isset($cats[$key])) continue; $lum = hex_luminance($hex); $light = ($lum + 0.05) / 0.05 > 1.05 / ($lum + 0.05); // whichever of black or white text reads better on this colour $cats[$key] = ['hex' => $hex, 'on' => $light ? '#0b0d12' : '#ffffff', 'end' => $light ? hex_mix($hex, 255, 0.22) : hex_mix($hex, 0, 0.38), 'text' => $lum > 0.16 ? hex_mix($hex, 0, 0.4) : $hex]; } // Every value is a checked hex colour (css_hex()); the cover address keeps only characters a CSS url("...") allows. $brand = css_hex($brand, '#0b0b0c'); $dark = css_hex($dark, '#1f4b5e'); $on = css_hex($on, '#ffffff'); $css = ''; foreach ($cats as $k => $c) { if (!preg_match('/^[0-9a-f]{6}$/', (string)$k)) continue; $css .= css_vars('.cat-' . $k, ['--cat' => css_hex($c['hex']), '--cat-on' => css_hex($c['on']), '--cat-end' => css_hex($c['end']), '--cat-text' => css_hex($c['text'])]); } $coverUrl = $cover ? (string)preg_replace('#[^a-zA-Z0-9/:._~%?&=+-]#', '', esc_url_raw(map_url($cover))) : ''; $bandImg = $coverUrl !== '' ? 'linear-gradient(100deg,' . $dark . 'f2 0%,' . $brand . 'cc 60%,' . $brand . '88 100%),url("' . $coverUrl . '")' : 'linear-gradient(100deg,' . $dark . ',' . $brand . ')'; $css .= css_vars('.tk', ['--brand' => $brand, '--dark' => $dark, '--on' => $on]) . '.tk-band{background-image:' . $bandImg . '}'; return [ 'brand' => $brand, 'dark' => $dark, 'on' => $on, 'logo' => $logo, 'brandName' => $brandName, 'place' => $place, 'times' => $times, 'css' => $css, 'foot' => trim(implode(' ยท ', array_filter([setting('footer_text') ?: $brandName, setting('support_email')]))), ]; }