/** * Icon — единый компонент иконок для KubikonEditor и KubikonStudio. * * Иконки — САМОПИСНЫЕ inline-SVG (не эмодзи, не сторонняя библиотека). * Единый стиль: viewBox 24×24, обводка currentColor, скруглённые концы. * Цвет наследуется от текста родителя (currentColor). * * Два режима использования: * * 1. По имени: * Семантическое имя (rename / delete / eye / settings / sun ...). * * 2. По эмодзи: * Маппит эмодзи на имя иконки. Используется когда иконка хранится * строкой в данных — менять структуру данных не нужно. * * Размер по умолчанию — 16px. Перебивается пропом size. * * Неизвестное имя/эмодзи → фолбэк-точка (видно, что иконка не настроена). */ import React from 'react'; // Общие пресеты атрибутов SVG-фигур. // Толщину обводки (stroke-width) задаём на самом — так её можно // переопределить пропом strokeWidth. Здесь её НЕ указываем. const S = { fill: 'none', stroke: 'currentColor', strokeLinecap: 'round', strokeLinejoin: 'round' }; const F = { fill: 'currentColor', stroke: 'none' }; // ---------------------------------------------------------------------------- // GLYPHS — реестр иконок. Ключ = имя, значение = функция, рисующая // внутренности (примитивы path/circle/rect/...). // ---------------------------------------------------------------------------- const GLYPHS = { // ===== действия ===== rename: () => (<>), edit: () => (<>), delete: () => (<>), trash: () => (<>), duplicate: () => (<>), copy: () => (<>), visible: () => (<>), hidden: () => (<>), eye: () => (<>), 'eye-off': () => (<>), locked: () => (<>), unlocked: () => (<>), select: () => (<>), cursor: () => (<>), move: () => (<>), scale: () => (<>), rotate: () => (<>), // ===== навигация / UI ===== add: () => (<>), plus: () => (<>), close: () => (<>), cancel: () => (<>), check: () => (<>), save: () => (<>), upload: () => (<>), download: () => (<>), publish: () => (<>), search: () => (<>), settings: () => (<>), sliders: () => (<>), more: () => (<>), chevronDown: () => (<>), chevronRight: () => (<>), folder: () => (<>), 'folder-open': () => (<>), 'folder-add': () => (<>), 'arrow-up': () => (<>), 'arrow-down': () => (<>), 'arrow-left': () => (<>), 'arrow-right': () => (<>), refresh: () => (<>), cycle: () => (<>), flag: () => (<>), star: () => (<>), award: () => (<>), warning: () => (<>), error: () => (<>), info: () => (<>), loading: () => (<>), bell: () => (<>), 'bell-off': () => (<>), image: () => (<>), camera: () => (<>), // ===== сцена / окружение ===== sun: () => (<>), moon: () => (<>), sunrise: () => (<>), sunset: () => (<>), cloud: () => (<>), fog: () => (<>), rain: () => (<>), wind: () => (<>), water: () => (<>), droplet: () => (<>), mountain: () => (<>), trees: () => (<>), tree: () => (<>), flower: () => (<>), sprout: () => (<>), leaf: () => (<>), plant: () => (<>), grass: () => (<>), bush: () => (<>), mushroom: () => (<>), stone: () => (<>), rock: () => (<>), snowflake: () => (<>), fire: () => (<>), waves: () => (<>), sparkle: () => (<>), sparkles: () => (<>), // ===== звук ===== music: () => (<>), music2: () => (<>), sound: () => (<>), mute: () => (<>), mic: () => (<>), // ===== мир / карта ===== globe: () => (<>), map: () => (<>), pin: () => (<>), compass: () => (<>), // ===== игрок / геймплей ===== user: () => (<>), avatar: () => (<>), users: () => (<>), heart: () => (<>), shield: () => (<>), sword: () => (<>), crosshair: () => (<>), target: () => (<>), zap: () => (<>), lightning: () => (<>), skull: () => (<>), bomb: () => (<>), crown: () => (<>), trophy: () => (<>), joystick: () => (<>), gamepad: () => (<>), backpack: () => (<>), box: () => (<>), hammer: () => (<>), wrench: () => (<>), pickaxe: () => (<>), bug: () => (<>), ghost: () => (<>), zombie: () => (<>), spawner: () => (<>), // ===== геометрия ===== cube: () => (<>), square: () => (<>), sphere: () => (<>), circle: () => (<>), triangle: () => (<>), hexagon: () => (<>), cylinder: () => (<>), cone: () => (<>), torus: () => (<>), boxes: () => (<>), layers: () => (<>), grid: () => (<>), archive: () => (<>), component: () => (<>), // ===== UI / художественные ===== palette: () => (<>), type: () => (<>), 'align-left': () => (<>), eraser: () => (<>), paintbrush: () => (<>), brush: () => (<>), highlighter: () => (<>), ruler: () => (<>), // ===== системные / медиа ===== play: () => (<>), pause: () => (<>), stop: () => (<>), forward: () => (<>), rewind: () => (<>), clock: () => (<>), hourglass: () => (<>), chat: () => (<>), message: () => (<>), file: () => (<>), 'file-code': () => (<>), code: () => (<>), script: () => (<>), clipboard: () => (<>), tag: () => (<>), anchor: () => (<>), magnet: () => (<>), link: () => (<>), flask: () => (<>), beaker: () => (<>), atom: () => (<>), home: () => (<>), building: () => (<>), door: () => (<>), construction: () => (<>), ladder: () => (<>), package: () => (<>), hash: () => (<>), // ===== прочее ===== flame: () => (<>), 'thumbs-up': () => (<>), 'thumbs-down': () => (<>), graduation: () => (<>), puzzle: () => (<>), smartphone: () => (<>), activity: () => (<>), book: () => (<>), 'book-open': () => (<>), 'book-text': () => (<>), library: () => (<>), trending: () => (<>), medal: () => (<>), baby: () => (<>), 'user-square': () => (<>), smile: () => (<>), bulb: () => (<>), keyboard: () => (<>), stethoscope: () => (<>), monitor: () => (<>), rocket: () => (<>), chart: () => (<>), 'bar-chart': () => (<>), radio: () => (<>), dice: () => (<>), swords: () => (<>), footprints: () => (<>), send: () => (<>), // ===== примитивы редактора 3D ===== 'prim-cube': () => (<>), 'prim-sphere': () => (<>), 'prim-cylinder': () => (<>), 'prim-cone': () => (<>), 'prim-plane': () => (<>), 'prim-torus': () => (<>), 'prim-wedge': () => (<>), 'prim-cornerwedge': () => (<>), 'prim-trigger': () => (<>), 'prim-checkpoint': () => (<>), 'prim-light': () => (<>), 'prim-emitter': () => (<>), 'prim-portal': () => (<>), 'prim-spike': () => (<>), 'prim-finish': () => (<>), 'prim-coin': () => (<>), // ===== тайлы редактора 3D ===== 'tile-floor': () => (<>), 'tile-spike': () => (<>), 'tile-orb': () => (<>), 'tile-pad': () => (<>), 'tile-gravity': () => (<>), 'tile-moving': () => (<>), 'tile-portal-square': () => (<>), 'tile-step': () => (<>), // ===== шаблоны ===== 'tpl-platformer': () => (<>), 'tpl-shooter': () => (<>), 'tpl-racing': () => (<>), 'tpl-plain': () => (<>), 'tpl-hills': () => (<>), 'tpl-island': () => (<>), 'tpl-city': () => (<>), 'tpl-village': () => (<>), }; // ---------------------------------------------------------------------------- // EMOJI → имя иконки. Для legacy-данных, где иконка приходит строкой-эмодзи. // ---------------------------------------------------------------------------- const EMOJI_TO_NAME = { // действия '✏️': 'rename', '✏': 'rename', '🗑️': 'delete', '🗑': 'delete', '📋': 'clipboard', '👁': 'visible', '👁️': 'visible', '🚫': 'hidden', '🔒': 'locked', '🔓': 'unlocked', '🎯': 'target', '✓': 'check', '✔': 'check', '✗': 'cancel', '✕': 'close', '❌': 'error', '⚠': 'warning', '⚠️': 'warning', '➕': 'add', // сцена / окружение '🌞': 'sun', '☀️': 'sun', '☀': 'sun', '🌙': 'moon', '🌑': 'moon', '🌅': 'sunset', '🌄': 'sunrise', '🌥️': 'cloud', '🌫️': 'fog', '💧': 'water', '💡': 'bulb', '✨': 'sparkles', '🌍': 'globe', '🌐': 'globe', '📍': 'pin', '🌲': 'tree', '🌳': 'trees', '🌸': 'flower', '🌼': 'flower', '🌱': 'sprout', '🌿': 'leaf', '🌾': 'grass', '🍄': 'mushroom', '🪨': 'rock', '🍩': 'torus', '⛰️': 'mountain', '⛰': 'mountain', // игрок / предметы '👤': 'user', '🧍': 'user', '🧟': 'zombie', '🌀': 'spawner', '❤️': 'heart', '🛡': 'shield', '🛡️': 'shield', '⚔️': 'swords', '⚔': 'swords', '🔱': 'sword', '🏹': 'target', '🔫': 'crosshair', '⚡': 'zap', '💣': 'bomb', '🏆': 'trophy', '⭐': 'star', '🎒': 'backpack', '🧪': 'flask', '🛠️': 'wrench', '🛠': 'wrench', '🩸': 'droplet', // геометрия '⬛': 'cube', '⬜': 'cube', '⚪': 'sphere', '🛢': 'cylinder', '🛢️': 'cylinder', '🔺': 'cone', '🔻': 'triangle', '▭': 'square', '🟦': 'square', '🟧': 'square', '🟢': 'circle', '🟥': 'square', '🟨': 'square', '🟩': 'square', '🟡': 'circle', '🟠': 'circle', '🔵': 'circle', '🟣': 'circle', '🟪': 'square', '🧱': 'boxes', '◣': 'prim-wedge', '◢': 'prim-cornerwedge', '〰': 'waves', // UI / художественные '🎨': 'palette', '📺': 'monitor', '🖼': 'image', '🖼️': 'image', '🔤': 'type', '🟧': 'square', // звук '🎵': 'music', '🎼': 'music2', '🔊': 'sound', // навигация '🔍': 'search', '📁': 'folder', '📂': 'folder-open', '⚙': 'settings', '⚙️': 'settings', '🔄': 'refresh', '↺': 'refresh', '🚩': 'flag', '🏁': 'flag', '🖱️': 'cursor', '🖱': 'cursor', '📐': 'ruler', '📏': 'ruler', '📤': 'upload', '📥': 'download', '📷': 'camera', '💾': 'save', '📝': 'rename', '📜': 'script', '🚪': 'door', '🚧': 'construction', '🪜': 'ladder', '🏠': 'home', '🏛️': 'building', '🏛': 'building', '⏱': 'clock', '⏳': 'hourglass', '🕒': 'clock', '⏹': 'stop', '▶': 'play', '▶️': 'play', '⏸': 'pause', '🎮': 'gamepad', '🎬': 'image', '📨': 'send', '📅': 'clock', '👶': 'baby', // прочее '🦘': 'zap', '⚓': 'anchor', '⚖️': 'sliders', '🔥': 'flame', '💨': 'wind', '🔮': 'sparkle', '👍': 'thumbs-up', '👎': 'thumbs-down', '🎓': 'graduation', '🧩': 'puzzle', '📱': 'smartphone', '📈': 'trending', '📊': 'chart', '📚': 'library', '📖': 'book-open', '📔': 'book-text', '🥇': 'trophy', '🥈': 'medal', '🥉': 'medal', '👑': 'crown', '🧒': 'baby', '👦': 'user', '🧑': 'user-square', '🧓': 'user-square', '👥': 'users', '🙂': 'smile', '💬': 'message', '💭': 'message', '⌨️': 'keyboard', '⌨': 'keyboard', '🩺': 'stethoscope', '🖥️': 'monitor', '🖥': 'monitor', '💻': 'monitor', '🚀': 'rocket', '🔴': 'radio', '💀': 'skull', '🎲': 'dice', '🏃': 'footprints', '🆕': 'sparkles', '🔞': 'shield', '🎉': 'sparkles', '🎂': 'star', '⬇': 'arrow-down', '←': 'arrow-left', '↓': 'arrow-down', '→': 'arrow-right', // транспорт / категории тулбокса '🚗': 'box', '⛵': 'box', '🛣': 'map', '🛸': 'prim-portal', '🤖': 'gamepad', '🏰': 'building', '🏡': 'home', '🏝️': 'tpl-island', '🏙️': 'tpl-city', '🪑': 'box', '🍕': 'box', '🎄': 'tree', '🪙': 'prim-coin', }; // ---------------------------------------------------------------------------- // FALLBACK — точка для неизвестных имён/эмодзи. // ---------------------------------------------------------------------------- function Fallback({ size = 16 }) { return ( ); } /** * * * * * strokeWidth — необязательный: задаёт толщину обводки (через CSS на svg, * переопределяет stroke-width дочерних фигур). Без него — 1.8 из пресета. */ export default function Icon({ name, emoji, size = 16, strokeWidth = 1.8, className, style }) { let key = name; if (!key && emoji) key = EMOJI_TO_NAME[emoji]; const draw = key && GLYPHS[key]; if (!draw) return ; return ( ); }