`(stroke 描边、currentColor * 取文字颜色),列表 / 卡片里直接内联;日历那种纯文本的地方用同一图标的 * emoji 兜底(`emo()`)—— 日历的事件标题是纯文本,塞不进 SVG。 * * ⚠️ **图标 key 是**契约**:它存在 settings(anniv_kinds)里,用户自己选。 * 所以:① 已有 key 永远不要改名(老数据会变成"认不出的图标"); * ② 新增图标只能往后加;③ 认不出的 key 一律回落 `dot`,不抛异常 * (用户可能手改过库、或跨版本导入过配置)。 * * @see \App\Anniversary::kindsFull() 分类清单(名称 + 图标)的读写 */ declare(strict_types=1); namespace App; final class AnnivIcon { /** 认不出/没配时用哪个 */ public const FALLBACK = 'dot'; /** * key => [中文名, emoji, SVG 内容(24×24 画布,stroke 描边)] * * ⚠️ SVG 内容里**不要**写 `fill` / `stroke` —— 由 svg() 统一给 * `fill="none" stroke="currentColor"`,这样图标颜色永远跟着所在位置的文字色, * 浅底深底都不会变成"看不见的黑块"。 */ public const LIST = [ 'cake' => ['蛋糕(生日)', '🎂', '' . '' . '' . '' . ''], 'ring' => ['戒指(结婚)', '💍', '' . '' . ''], 'heart' => ['爱心(相识/恋爱)', '❤️', ''], 'candle' => ['蜡烛(忌日/追思)', '🕯️', '' . '' . '' . ''], 'star' => ['星星(节日)', '⭐', ''], 'gift' => ['礼物', '🎁', '' . '' . '' . ''], 'baby' => ['孩子(满月/出生)', '👶', '' . '' . ''], 'home' => ['家(搬家/乔迁)', '🏠', '' . ''], 'book' => ['书(毕业/升学)', '📖', '' . ''], 'plane' => ['飞机(远行/旅行)', '✈️', ''], 'camera' => ['相机(合影/留念)', '📷', '' . '' . ''], 'music' => ['音符(音乐/演出)', '🎵', '' . '' . ''], 'trophy' => ['奖杯(成就/晋升)', '🏆', '' . '' . '' . ''], 'clock' => ['时钟(周年/入职)', '⏰', '' . ''], 'flower' => ['花(表白/祝福)', '🌸', '' . '' . '' . '' . '' . ''], 'leaf' => ['叶(自然而然)', '🌿', '' . ''], 'bell' => ['铃铛(提醒/纪念)', '🔔', '' . '' . ''], 'dot' => ['圆点(其它)', '⚪', ''], ]; public static function has(string $key): bool { return $key !== '' && isset(self::LIST[$key]); } /** 认不出的 key 一律回落,绝不抛异常(配置可能来自旧版本/手改) */ public static function normalize(string $key): string { $key = strtolower(trim($key)); return self::has($key) ? $key : self::FALLBACK; } /** 中文名(给设置页的下拉用) */ public static function label(string $key): string { return self::LIST[self::normalize($key)][0]; } public static function emo(string $key): string { return self::LIST[self::normalize($key)][1]; } /** * 行内 SVG。 * * ⚠️ 返回值是**可信 HTML**(不含任何用户输入:key 先 normalize,size 转 int), * 模板里直接 `` 输出,不要 e() 一遍(那会把标签转义成文字)。 * aria-hidden:图标永远是"文字旁边的装饰",读屏器念分类名就够了。 */ public static function svg(string $key, int $size = 15, string $cls = ''): string { $k = self::normalize($key); $n = max(8, min(96, $size)); return ''; } /** 设置页下拉里能选的全部图标:key => "emoji 中文名" */ public static function choices(): array { $out = []; foreach (self::LIST as $k => $v) { $out[$k] = $v[1] . ' ' . $v[0]; } return $out; } }