feat: custom recipe cover color/icon + mute auto placeholder palette (v0.51.0)
Two changes to the no-photo cover placeholder shipped last version: 1. Muted the gradient palette (100/40-opacity tints instead of solid -200/ -950 stops) — the original was too saturated next to real cover photos in the same grid, per feedback. 2. New coverIcon/coverColor columns on recipes (nullable text, migration 0048, additive-only) let the author pin a specific color+icon from the recipe editor instead of the automatic per-id pick. getRecipePlaceholder now checks these first, falling back to the deterministic hash pick when unset — existing recipes are unaffected until edited. Wired coverIcon/coverColor through every explicit-column recipe select that feeds a grid card (explore trending/recent, search, feed, for-you) — the relational-query call sites (recipes page, collections, profile pages) already return all columns and needed no changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,8 @@ export function generateOpenApiSpec(): object {
|
||||
difficulty: z.enum(["easy", "medium", "hard"]).nullable(),
|
||||
prepMins: z.number().int().nullable(), cookMins: z.number().int().nullable(),
|
||||
tags: z.array(z.string()), sourceUrl: z.string().nullable(), language: z.string().nullable(),
|
||||
coverIcon: z.string().nullable().describe("Cover placeholder icon key, used when there's no photo. Null falls back to a deterministic pick from the recipe id."),
|
||||
coverColor: z.string().nullable().describe("Cover placeholder gradient key, used when there's no photo. Null falls back to a deterministic pick from the recipe id."),
|
||||
isBatchCook: z.boolean(), nutritionData: z.object({ perServing: NutritionInputRef }).nullable(),
|
||||
nutritionManual: z.boolean().describe("True if nutritionData was entered by the author rather than AI-estimated."),
|
||||
dietaryTags: DietaryTagsRef, aiGenerated: z.boolean(),
|
||||
@@ -77,6 +79,7 @@ export function generateOpenApiSpec(): object {
|
||||
prepMins: z.number().int().nullable(), cookMins: z.number().int().nullable(),
|
||||
tags: z.array(z.string()), dietaryTags: DietaryTagsRef, aiGenerated: z.boolean(),
|
||||
language: z.string().nullable(), sourceUrl: z.string().nullable(),
|
||||
coverIcon: z.string().nullable(), coverColor: z.string().nullable(),
|
||||
isBatchCook: z.boolean(), nutritionData: z.object({ perServing: NutritionInputRef }).nullable(),
|
||||
nutritionManual: z.boolean(),
|
||||
createdAt: z.string().datetime(), updatedAt: z.string().datetime(),
|
||||
@@ -113,6 +116,8 @@ export function generateOpenApiSpec(): object {
|
||||
key: z.string().min(1).max(500),
|
||||
isCover: z.boolean().default(false),
|
||||
})).max(20).default([]),
|
||||
coverIcon: z.string().max(50).nullable().optional(),
|
||||
coverColor: z.string().max(50).nullable().optional(),
|
||||
isBatchCook: z.boolean().default(false),
|
||||
dishes: z.array(z.object({
|
||||
name: z.string().min(1).max(100),
|
||||
@@ -155,6 +160,8 @@ export function generateOpenApiSpec(): object {
|
||||
key: z.string().min(1).max(500),
|
||||
isCover: z.boolean().default(false),
|
||||
})).max(20).optional(),
|
||||
coverIcon: z.string().max(50).nullable().optional(),
|
||||
coverColor: z.string().max(50).nullable().optional(),
|
||||
isBatchCook: z.boolean().optional(),
|
||||
dishes: z.array(z.object({
|
||||
name: z.string().min(1).max(100),
|
||||
|
||||
Reference in New Issue
Block a user