Wire admin studio SSR and search infrastructure
This commit is contained in:
@@ -145,20 +145,32 @@ class NovaCardRenderService
|
||||
private function paintOverlay($image, array $project, int $width, int $height): void
|
||||
{
|
||||
$style = (string) Arr::get($project, 'background.overlay_style', 'dark-soft');
|
||||
$alpha = match ($style) {
|
||||
'dark-strong' => 72,
|
||||
'dark-soft' => 92,
|
||||
'light-soft' => 108,
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($alpha === null) {
|
||||
if ($style === 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Respect the opacity slider (0–100 %) that the CSS preview applies to the overlay div.
|
||||
$opacityPct = max(0, min(100, (int) Arr::get($project, 'background.opacity', 50)));
|
||||
$scale = $opacityPct / 100.0;
|
||||
|
||||
// Top/bottom gradient stop opacities — matches overlayStyle() in NovaCardCanvasPreview.jsx:
|
||||
// dark-soft: linear-gradient(180deg, rgba(2,6,23,0.18), rgba(2,6,23,0.48))
|
||||
// dark-strong: linear-gradient(180deg, rgba(2,6,23,0.38), rgba(2,6,23,0.68))
|
||||
// light-soft: linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.22))
|
||||
[$topA, $botA] = match ($style) {
|
||||
'dark-strong' => [0.38, 0.68],
|
||||
'light-soft' => [0.08, 0.22],
|
||||
default => [0.18, 0.48], // dark-soft
|
||||
};
|
||||
$rgb = $style === 'light-soft' ? [255, 255, 255] : [0, 0, 0];
|
||||
$overlay = imagecolorallocatealpha($image, $rgb[0], $rgb[1], $rgb[2], $alpha);
|
||||
imagefilledrectangle($image, 0, 0, $width, $height, $overlay);
|
||||
|
||||
// Draw a scanline gradient to match the CSS linear-gradient overlay.
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
$alpha = ($topA + ($botA - $topA) * ($y / $height)) * $scale;
|
||||
$gdAlpha = max(0, min(127, (int) round((1.0 - $alpha) * 127)));
|
||||
$color = imagecolorallocatealpha($image, $rgb[0], $rgb[1], $rgb[2], $gdAlpha);
|
||||
imageline($image, 0, $y, $width - 1, $y, $color);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Text rendering (FreeType / GD fallback) ─────────────────────────────
|
||||
@@ -167,10 +179,15 @@ class NovaCardRenderService
|
||||
{
|
||||
$fontPreset = (string) Arr::get($project, 'typography.font_preset', 'modern-sans');
|
||||
$fontFile = $this->resolveFont($fontPreset);
|
||||
$textColor = $this->allocateHex($image, (string) Arr::get($project, 'typography.text_color', '#ffffff'));
|
||||
$accentColor = $this->allocateHex($image, (string) Arr::get($project, 'typography.accent_color', Arr::get($project, 'typography.text_color', '#ffffff')));
|
||||
// Apply text_opacity (10–100 %) to both text and accent colours, matching CSS blockStyle().
|
||||
$textOpacityPct = max(10, min(100, (int) Arr::get($project, 'typography.text_opacity', 100)));
|
||||
$textAlpha = (int) round((1.0 - $textOpacityPct / 100.0) * 127);
|
||||
[$tr, $tg, $tb] = $this->hexToRgb((string) Arr::get($project, 'typography.text_color', '#ffffff'));
|
||||
[$ar, $ag, $ab] = $this->hexToRgb((string) Arr::get($project, 'typography.accent_color', Arr::get($project, 'typography.text_color', '#ffffff')));
|
||||
$textColor = imagecolorallocatealpha($image, $tr, $tg, $tb, $textAlpha);
|
||||
$accentColor = imagecolorallocatealpha($image, $ar, $ag, $ab, $textAlpha);
|
||||
$alignment = (string) Arr::get($project, 'layout.alignment', 'center');
|
||||
$lhMulti = (float) Arr::get($project, 'typography.line_height', 1.35);
|
||||
$lhMulti = (float) Arr::get($project, 'typography.line_height', 1.2);
|
||||
$shadow = (string) Arr::get($project, 'typography.shadow_preset', 'soft');
|
||||
|
||||
$paddingRatio = match ((string) Arr::get($project, 'layout.padding', 'comfortable')) {
|
||||
@@ -400,15 +417,22 @@ class NovaCardRenderService
|
||||
foreach (array_slice($decorations, 0, (int) config('nova_cards.validation.max_decorations', 6)) as $index => $decoration) {
|
||||
$glyph = (string) Arr::get($decoration, 'glyph', '•');
|
||||
|
||||
// pos_x / pos_y are stored as percentages (0–100); fall back to sensible defaults.
|
||||
// pos_x / pos_y are stored as percentages (0–100); when absent, fall back to
|
||||
// `placement` field — mirroring placementStyles in NovaCardCanvasPreview.jsx.
|
||||
$xPct = Arr::get($decoration, 'pos_x');
|
||||
$yPct = Arr::get($decoration, 'pos_y');
|
||||
$x = $xPct !== null
|
||||
? (int) round((float) $xPct / 100 * $width)
|
||||
: (int) round(($index % 2 === 0 ? 0.12 : 0.82) * $width);
|
||||
$y = $yPct !== null
|
||||
? (int) round((float) $yPct / 100 * $height)
|
||||
: (int) round((0.14 + ($index * 0.1)) * $height);
|
||||
if ($xPct !== null && $yPct !== null) {
|
||||
$x = (int) round((float) $xPct / 100 * $width);
|
||||
$y = (int) round((float) $yPct / 100 * $height);
|
||||
} else {
|
||||
$placement = (string) Arr::get($decoration, 'placement', 'top-right');
|
||||
$x = str_contains($placement, 'left') ? (int) round(0.12 * $width)
|
||||
: (str_contains($placement, 'right') ? (int) round(0.88 * $width)
|
||||
: (int) round(0.50 * $width));
|
||||
$y = str_contains($placement, 'top') ? (int) round(0.12 * $height)
|
||||
: (str_contains($placement, 'bottom') ? (int) round(0.88 * $height)
|
||||
: (int) round(0.50 * $height));
|
||||
}
|
||||
|
||||
// Canvas clamp: max(18, min(size, 64)) matching NovaCardCanvasPreview.
|
||||
$rawSize = max(18, min((int) Arr::get($decoration, 'size', 28), 64));
|
||||
|
||||
Reference in New Issue
Block a user