diff --git a/src/app/globals.css b/src/app/globals.css index 67018c5..5aa51c1 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -249,6 +249,28 @@ body { filter: drop-shadow(0 0 3px rgba(var(--color-primary), 0.3)); } + /* 选项按钮样式 */ + .btn-option { + @apply px-3 py-1.5 rounded-md border text-sm font-medium transition-all; + background-color: rgb(var(--color-bg-secondary)); + color: rgb(var(--color-text-secondary)); + border-color: rgba(var(--color-primary), 0.1); + } + + .btn-option:hover { + border-color: rgba(var(--color-primary), 0.5); + color: rgb(var(--color-text-primary)); + background-color: rgba(var(--color-primary), 0.1); + } + + .btn-option-active { + @apply px-3 py-1.5 rounded-md border text-sm font-medium transition-all; + background: linear-gradient(to right, rgb(var(--color-primary)), rgb(var(--color-primary-hover))); + color: white; + border-color: rgba(var(--color-primary), 0.7); + box-shadow: 0 2px 4px rgba(var(--color-primary), 0.4); + } + /* 圆角按钮 */ .rounded-button { @apply rounded-md; diff --git a/src/app/tools/icon_designer/components/EnhancedIconCanvas.tsx b/src/app/tools/icon_designer/components/EnhancedIconCanvas.tsx new file mode 100644 index 0000000..bb0aa2d --- /dev/null +++ b/src/app/tools/icon_designer/components/EnhancedIconCanvas.tsx @@ -0,0 +1,246 @@ +'use client'; + +import React, { useRef, useEffect, forwardRef, useImperativeHandle } from 'react'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; +import { BackgroundType, IconType, ShapeType } from './EnhancedIconPreview'; + +interface EnhancedIconCanvasProps { + // 图标相关 + iconType: IconType; + icon?: IconDefinition; + customText?: string; + iconColor: string; + iconSize: number; + iconRotation: number; + fontFamily?: string; + fontWeight?: string; + + // 背景相关 + backgroundType: BackgroundType; + backgroundColor: string; + gradientStartColor?: string; + gradientEndColor?: string; + gradientDirection?: number; + shape: ShapeType; + + canvasSize?: number; +} + +export interface EnhancedIconCanvasRef { + getCanvas: () => HTMLCanvasElement | null; + generateIcon: (size: number) => Promise; +} + +const EnhancedIconCanvas = forwardRef(({ + iconType, + icon, + customText, + iconColor, + iconSize, + iconRotation, + fontFamily = 'Arial, sans-serif', + fontWeight = 'normal', + backgroundType, + backgroundColor, + gradientStartColor, + gradientEndColor, + gradientDirection = 45, + shape, + canvasSize = 200 +}, ref) => { + const canvasRef = useRef(null); + + // 创建渐变 + const createGradient = (ctx: CanvasRenderingContext2D, size: number) => { + if (!gradientStartColor || !gradientEndColor) return null; + + if (backgroundType === 'linear-gradient') { + const angle = (gradientDirection * Math.PI) / 180; + const x1 = size / 2 - (Math.cos(angle) * size) / 2; + const y1 = size / 2 - (Math.sin(angle) * size) / 2; + const x2 = size / 2 + (Math.cos(angle) * size) / 2; + const y2 = size / 2 + (Math.sin(angle) * size) / 2; + + const gradient = ctx.createLinearGradient(x1, y1, x2, y2); + gradient.addColorStop(0, gradientStartColor); + gradient.addColorStop(1, gradientEndColor); + return gradient; + } else if (backgroundType === 'radial-gradient') { + const gradient = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2); + gradient.addColorStop(0, gradientStartColor); + gradient.addColorStop(1, gradientEndColor); + return gradient; + } + + return null; + }; + + // 独立的绘制函数 + const drawIconToContext = React.useCallback(async (ctx: CanvasRenderingContext2D, size: number) => { + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = 'high'; + ctx.clearRect(0, 0, size, size); + + // 绘制背景 + const padding = (size * 5) / 200; + const backgroundSize = size - padding * 2; + + // 设置背景颜色或渐变 + const gradient = createGradient(ctx, size); + ctx.fillStyle = gradient || backgroundColor; + + switch (shape) { + case 'circle': + ctx.beginPath(); + ctx.arc(size / 2, size / 2, backgroundSize / 2, 0, 2 * Math.PI); + ctx.fill(); + break; + case 'square': + ctx.fillRect(padding, padding, backgroundSize, backgroundSize); + break; + case 'rounded-square': + ctx.beginPath(); + const radius = backgroundSize * 0.15; + ctx.roundRect(padding, padding, backgroundSize, backgroundSize, radius); + ctx.fill(); + break; + case 'hexagon': + const centerX = size / 2; + const centerY = size / 2; + const hexRadius = backgroundSize / 2; + ctx.beginPath(); + for (let i = 0; i < 6; i++) { + const angle = (i * Math.PI) / 3; + const x = centerX + hexRadius * Math.cos(angle); + const y = centerY + hexRadius * Math.sin(angle); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.closePath(); + ctx.fill(); + break; + } + + // 绘制图标或文字 + const iconDrawSize = (size * iconSize) / 100; + const iconX = size / 2; + const iconY = size / 2; + + ctx.save(); + ctx.translate(iconX, iconY); + ctx.rotate((iconRotation * Math.PI) / 180); + + if (iconType === 'text' && customText) { + // 绘制自定义文字 + ctx.fillStyle = iconColor; + ctx.font = `${fontWeight} ${iconDrawSize}px ${fontFamily}`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(customText, 0, 0); + } else if (iconType === 'fontawesome' && icon) { + // 绘制FontAwesome图标 + try { + const svgString = ` + + + + `; + + const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); + const svgUrl = URL.createObjectURL(svgBlob); + const img = new Image(); + + await new Promise((resolve) => { + img.onload = () => { + ctx.drawImage(img, -iconDrawSize / 2, -iconDrawSize / 2, iconDrawSize, iconDrawSize); + URL.revokeObjectURL(svgUrl); + resolve(); + }; + + img.onerror = () => { + URL.revokeObjectURL(svgUrl); + // 降级方案:绘制一个圆点 + ctx.fillStyle = iconColor; + ctx.beginPath(); + ctx.arc(0, 0, iconDrawSize / 4, 0, 2 * Math.PI); + ctx.fill(); + resolve(); + }; + + img.src = svgUrl; + }); + } catch (error) { + console.error('绘制图标失败:', error); + // 降级方案 + ctx.fillStyle = iconColor; + ctx.beginPath(); + ctx.arc(0, 0, iconDrawSize / 4, 0, 2 * Math.PI); + ctx.fill(); + } + } + + ctx.restore(); + }, [iconType, icon, customText, iconColor, iconSize, iconRotation, fontFamily, fontWeight, backgroundType, backgroundColor, gradientStartColor, gradientEndColor, gradientDirection, shape]); + + // 绘制到当前画布 + const drawIcon = React.useCallback(async () => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + canvas.width = canvasSize; + canvas.height = canvasSize; + + await drawIconToContext(ctx, canvasSize); + }, [drawIconToContext, canvasSize]); + + // 生成指定尺寸的图标 + const generateIcon = React.useCallback(async (size: number): Promise => { + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + + if (!tempCtx) { + throw new Error('无法创建画布'); + } + + tempCanvas.width = size; + tempCanvas.height = size; + + tempCtx.imageSmoothingEnabled = true; + tempCtx.imageSmoothingQuality = 'high'; + + await drawIconToContext(tempCtx, size); + + return tempCanvas.toDataURL('image/png'); + }, [drawIconToContext]); + + // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + getCanvas: () => canvasRef.current, + generateIcon + }), [generateIcon]); + + // 当参数变化时重新绘制 + useEffect(() => { + drawIcon().catch(console.error); + }, [drawIcon]); + + return ( + + ); +}); + +EnhancedIconCanvas.displayName = 'EnhancedIconCanvas'; + +export default EnhancedIconCanvas; \ No newline at end of file diff --git a/src/app/tools/icon_designer/components/EnhancedIconPreview.tsx b/src/app/tools/icon_designer/components/EnhancedIconPreview.tsx new file mode 100644 index 0000000..f767f8c --- /dev/null +++ b/src/app/tools/icon_designer/components/EnhancedIconPreview.tsx @@ -0,0 +1,177 @@ +'use client'; + +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; + +export type ShapeType = 'circle' | 'square' | 'rounded-square' | 'hexagon'; +export type BackgroundType = 'solid' | 'linear-gradient' | 'radial-gradient'; +export type IconType = 'fontawesome' | 'text'; + +interface EnhancedIconPreviewProps { + // 图标相关 + iconType: IconType; + icon?: IconDefinition; + customText?: string; + iconColor: string; + iconSize: number; + iconRotation: number; + fontFamily?: string; + fontWeight?: string; + + // 背景相关 + backgroundType: BackgroundType; + backgroundColor: string; + gradientStartColor?: string; + gradientEndColor?: string; + gradientDirection?: number; // 角度 + shape: ShapeType; + + // 其他 + previewSize?: number; +} + +export default function EnhancedIconPreview({ + iconType, + icon, + customText, + iconColor, + iconSize, + iconRotation, + fontFamily = 'Arial, sans-serif', + fontWeight = 'normal', + backgroundType, + backgroundColor, + gradientStartColor, + gradientEndColor, + gradientDirection = 45, + shape, + previewSize = 200 +}: EnhancedIconPreviewProps) { + + // 获取背景样式 + const getBackgroundStyle = () => { + switch (backgroundType) { + case 'linear-gradient': + if (gradientStartColor && gradientEndColor) { + return { + background: `linear-gradient(${gradientDirection}deg, ${gradientStartColor}, ${gradientEndColor})` + }; + } + break; + case 'radial-gradient': + if (gradientStartColor && gradientEndColor) { + return { + background: `radial-gradient(circle, ${gradientStartColor}, ${gradientEndColor})` + }; + } + break; + case 'solid': + default: + return { + backgroundColor: backgroundColor + }; + } + return { backgroundColor: backgroundColor }; + }; + + // 根据形状生成CSS类和额外样式 + const getShapeStyle = () => { + const baseStyle = { + width: `${previewSize}px`, + height: `${previewSize}px`, + position: 'relative' as const, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + overflow: 'hidden', + ...getBackgroundStyle() + }; + + switch (shape) { + case 'circle': + return { + ...baseStyle, + borderRadius: '50%' + }; + case 'square': + return baseStyle; + case 'rounded-square': + return { + ...baseStyle, + borderRadius: `${previewSize * 0.15}px` + }; + case 'hexagon': + return { + ...baseStyle, + clipPath: 'polygon(25% 6.7%, 75% 6.7%, 100% 50%, 75% 93.3%, 25% 93.3%, 0% 50%)' + }; + default: + return baseStyle; + } + }; + + // 计算图标/文字大小 + const calculateIconSize = () => { + return (previewSize * iconSize) / 100; + }; + + // 渲染图标内容 + const renderIconContent = () => { + const iconStyle = { + color: iconColor, + fontSize: `${calculateIconSize()}px`, + transform: `rotate(${iconRotation}deg)`, + transition: 'all 0.3s ease', + userSelect: 'none' as const + }; + + if (iconType === 'text' && customText) { + return ( + + {customText} + + ); + } else if (iconType === 'fontawesome' && icon) { + return ( + + ); + } + + return null; + }; + + return ( +
+
+ {renderIconContent()} +
+ +
+

+ {iconType === 'text' + ? `"${customText || 'Text'}" • ${shape} • ${iconSize}% • ${iconRotation}°` + : `${icon?.iconName || 'Icon'} • ${shape} • ${iconSize}% • ${iconRotation}°` + } +

+

+ {backgroundType === 'solid' + ? `背景: ${backgroundColor}` + : `背景: ${backgroundType} (${gradientStartColor} → ${gradientEndColor})` + } +

+
+
+ ); +} \ No newline at end of file diff --git a/src/app/tools/icon_designer/components/IconCanvas.tsx b/src/app/tools/icon_designer/components/IconCanvas.tsx new file mode 100644 index 0000000..3dee5d8 --- /dev/null +++ b/src/app/tools/icon_designer/components/IconCanvas.tsx @@ -0,0 +1,227 @@ +'use client'; + +import React, { useRef, useEffect, forwardRef, useImperativeHandle } from 'react'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { fas } from '@fortawesome/free-solid-svg-icons'; + +// 添加所有FontAwesome图标到库中 +library.add(fas); + +export type ShapeType = 'circle' | 'square' | 'rounded-square' | 'hexagon'; + +interface IconCanvasProps { + icon: IconDefinition; + backgroundColor: string; + iconColor: string; + shape: ShapeType; + iconSize: number; + canvasSize?: number; +} + +export interface IconCanvasRef { + getCanvas: () => HTMLCanvasElement | null; + generateIcon: (size: number) => Promise; +} + +const IconCanvas = forwardRef(({ + icon, + backgroundColor, + iconColor, + shape, + iconSize, + canvasSize = 200 +}, ref) => { + const canvasRef = useRef(null); + + // 独立的绘制函数,可以绘制到任意context和尺寸 + const drawIconToContext = React.useCallback(async (ctx: CanvasRenderingContext2D, size: number) => { + // 启用抗锯齿设置 + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = 'high'; + + // 清空画布 + ctx.clearRect(0, 0, size, size); + + // 绘制背景 + ctx.fillStyle = backgroundColor; + + const padding = (size * 5) / 200; // 按比例调整padding + const backgroundSize = size - padding * 2; + + switch (shape) { + case 'circle': + ctx.beginPath(); + ctx.arc(size / 2, size / 2, backgroundSize / 2, 0, 2 * Math.PI); + ctx.fill(); + break; + case 'square': + ctx.fillRect(padding, padding, backgroundSize, backgroundSize); + break; + case 'rounded-square': + ctx.beginPath(); + const radius = backgroundSize * 0.15; // 15% 圆角 + ctx.roundRect(padding, padding, backgroundSize, backgroundSize, radius); + ctx.fill(); + break; + case 'hexagon': + const centerX = size / 2; + const centerY = size / 2; + const hexRadius = backgroundSize / 2; + ctx.beginPath(); + for (let i = 0; i < 6; i++) { + const angle = (i * Math.PI) / 3; + const x = centerX + hexRadius * Math.cos(angle); + const y = centerY + hexRadius * Math.sin(angle); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.closePath(); + ctx.fill(); + break; + } + + // 绘制FontAwesome图标 + try { + // 创建SVG字符串 + const svgString = ` + + + + `; + + // 将SVG转换为blob URL + const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); + const svgUrl = URL.createObjectURL(svgBlob); + + // 创建图片对象 + const img = new Image(); + + return new Promise((resolve) => { + img.onload = () => { + // 计算图标绘制位置和大小 + const iconDrawSize = (size * iconSize) / 100; + const iconX = (size - iconDrawSize) / 2; + const iconY = (size - iconDrawSize) / 2; + + // 绘制图标 + ctx.drawImage(img, iconX, iconY, iconDrawSize, iconDrawSize); + + // 清理URL + URL.revokeObjectURL(svgUrl); + resolve(); + }; + + img.onerror = () => { + // 如果SVG加载失败,使用降级方案 + URL.revokeObjectURL(svgUrl); + + // 降级方案:使用文字符号 + ctx.fillStyle = iconColor; + const fontSize = (size * iconSize) / 300; // 调整字体大小 + ctx.font = `${fontSize}px Arial`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + // 使用emoji符号作为降级 + const fallbackSymbols: Record = { + 'heart': '♥', + 'star': '★', + 'home': '⌂', + 'user': '👤', + 'envelope': '✉', + 'phone': '📞', + 'shopping-cart': '🛒', + 'play': '▶', + 'music': '♪', + 'camera': '📷', + 'gift': '🎁', + 'check': '✓', + 'bookmark': '🔖', + 'coffee': '☕', + }; + + const symbol = fallbackSymbols[icon.iconName] || '●'; + ctx.fillText(symbol, size / 2, size / 2); + resolve(); + }; + + img.src = svgUrl; + }); + + } catch (error) { + console.error('绘制图标失败:', error); + + // 最终降级方案:绘制一个简单的圆点 + ctx.fillStyle = iconColor; + ctx.beginPath(); + const dotRadius = (size * iconSize) / 400; + ctx.arc(size / 2, size / 2, dotRadius, 0, 2 * Math.PI); + ctx.fill(); + } + }, [icon, backgroundColor, iconColor, shape, iconSize]); + + // 绘制图标到画布 + const drawIcon = React.useCallback(async () => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + canvas.width = canvasSize; + canvas.height = canvasSize; + + await drawIconToContext(ctx, canvasSize); + }, [drawIconToContext, canvasSize]); + + // 生成指定尺寸的图标 + const generateIcon = React.useCallback(async (size: number): Promise => { + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + + if (!tempCtx || !canvasRef.current) { + throw new Error('无法创建画布'); + } + + tempCanvas.width = size; + tempCanvas.height = size; + + // 启用高质量抗锯齿 + tempCtx.imageSmoothingEnabled = true; + tempCtx.imageSmoothingQuality = 'high'; + + // 始终重新绘制以获得最佳质量 + await drawIconToContext(tempCtx, size); + + return tempCanvas.toDataURL('image/png'); + }, [canvasSize, drawIconToContext]); + + // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + getCanvas: () => canvasRef.current, + generateIcon + }), [generateIcon]); + + // 当参数变化时重新绘制 + useEffect(() => { + drawIcon().catch(console.error); + }, [drawIcon]); + + return ( + + ); +}); + +IconCanvas.displayName = 'IconCanvas'; + +export default IconCanvas; \ No newline at end of file diff --git a/src/app/tools/icon_designer/components/IconPreview.tsx b/src/app/tools/icon_designer/components/IconPreview.tsx new file mode 100644 index 0000000..ce0d7e2 --- /dev/null +++ b/src/app/tools/icon_designer/components/IconPreview.tsx @@ -0,0 +1,75 @@ +'use client'; + +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; + +export type ShapeType = 'circle' | 'square' | 'rounded-square' | 'hexagon'; + +interface IconPreviewProps { + icon: IconDefinition; + backgroundColor: string; + iconColor: string; + shape: ShapeType; + iconSize: number; + previewSize?: number; +} + +export default function IconPreview({ + icon, + backgroundColor, + iconColor, + shape, + iconSize, + previewSize = 200 +}: IconPreviewProps) { + + // 根据形状生成CSS类 + const getShapeClass = () => { + switch (shape) { + case 'circle': + return 'rounded-full'; + case 'square': + return ''; + case 'rounded-square': + return 'rounded-xl'; + case 'hexagon': + return 'rounded-lg transform rotate-45'; // 简化为圆角,真正的六边形需要clip-path + default: + return ''; + } + }; + + // 计算图标大小 + const calculateIconSize = () => { + return (previewSize * iconSize) / 100; + }; + + return ( +
+
+ +
+ +
+

+ {icon.iconName} • {shape} • {iconSize}% +

+
+
+ ); +} \ No newline at end of file diff --git a/src/app/tools/icon_designer/components/IconSelector.tsx b/src/app/tools/icon_designer/components/IconSelector.tsx new file mode 100644 index 0000000..c0d594c --- /dev/null +++ b/src/app/tools/icon_designer/components/IconSelector.tsx @@ -0,0 +1,425 @@ +'use client'; + +import React, { useState, useMemo } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; +import { + // 常用图标 + faHeart, faStar, faHome, faUser, faEnvelope, faPhone, faShoppingCart, faPlay, + faMusic, faCamera, faGift, faCheck, faBookmark, faCoffee, faGamepad, faBell, + faSearch, faDownload, faUpload, faShare, faCog, faThumbsUp, faThumbsDown, + faFire, faEye, faEyeSlash, faVolumeMute, faVolumeUp, faMicrophone, faMicrophoneSlash, + + // 商务图标 + faChartBar, faFile, faFolder, faCogs, faWrench, faRocket, faLightbulb, + faDatabase, faCode, faBug, faEdit, faCopy, faTrash, faSave, faPrint, + faBriefcase, faBuilding, faIndustry, faHandshake, faMoneyBill, faCreditCard, + faChartLine, faChartPie, faCalculator, faClipboard, faFileAlt, faFilePdf, + faFileWord, faFileExcel, faFilePowerpoint, faFileImage, faFileVideo, faFileAudio, + + // 科技图标 + faCloud, faServer, faLaptop, faDesktop, faMobile, faTablet, + faShieldAlt, faLock, faKey, faGlobe, faWifi, + faHdd, faSdCard, faMemory, faBatteryFull, faBatteryHalf, faBatteryEmpty, + faPlug, faPowerOff, faSignal, faRss, faQrcode, + + // 社交图标 + faUsers, faUserFriends, faUserPlus, faUserMinus, faComments, faComment, + faCommentDots, faReply, faRetweet, faHashtag, faAt, faQuoteLeft, faQuoteRight, + faPaperPlane, faInbox, faEnvelopeOpen, faEnvelopeOpenText, faAddressBook, + faIdCard, faIdBadge, faUserTag, faUserCheck, faUserTimes, + + // 界面图标 + faPlus, faMinus, faTimes, faArrowRight, faArrowLeft, faArrowUp, faArrowDown, + faSync, faRedo, faUndo, faRefresh, faExpand, faCompress, faMaximize, faMinimize, + faAngleUp, faAngleDown, faAngleLeft, faAngleRight, faChevronUp, faChevronDown, + faChevronLeft, faChevronRight, faCaretUp, faCaretDown, faCaretLeft, faCaretRight, + faSort, faSortUp, faSortDown, faFilter, faBars, faEllipsisH, faEllipsisV, + faGripHorizontal, faGripVertical, faGripLines, faGripLinesVertical, + + // 媒体图标 + faPause, faStop, faStepForward, faStepBackward, faFastForward, faFastBackward, + faRandom, faRepeat, faVolumeDown, faVolumeOff, faHeadphones, + faVideo, faVideoSlash, faImage, faImages, faPhotoVideo, faFilm, + faCameraRetro, faRecordVinyl, faCompactDisc, faTv, faRadio, faPodcast, + + // 交通出行 + faCar, faTruck, faBus, faTaxi, faMotorcycle, faBicycle, faPlane, faTrain, + faShip, faSubway, faWalking, faRunning, faMapMarkerAlt, faMap, faRoute, + faCompass, faLocationArrow, faStreetView, faRoad, faParking, faGasPump, + + // 购物电商 + faShoppingBag, faShoppingBasket, faStoreAlt, faStore, faReceipt, faBarcode, + faTags, faPercent, faGem, faCrown, faAward, faMedal, faTrophy, faRibbon, + faGifts, faBox, faBoxOpen, faBoxes, faWarehouse, faShippingFast, + + // 健康医疗 + faHeart as faHeartSolid, faHeartbeat, faStethoscope, faUserMd, faHospital, + faAmbulance, faPills, faSyringe, faThermometer, faBandAid, faFirstAid, + faDna, faMicroscope, faXRay, faTeeth, faEye as faEyeMedical, faBrain, + + // 食物饮料 + faUtensils, faUtensilSpoon, faCocktail, faWineGlass, + faBeer, faPizzaSlice, faHamburger, faHotdog, faIceCream, faCake, + faAppleAlt, faCarrot, faCheese, faFish, faEgg, faBacon, faBreadSlice, + + // 运动休闲 + faFutbol, faBasketballBall, faBaseballBall, faFootballBall, faVolleyballBall, + faTableTennis, faGolfBall, faBowlingBall, faHockeyPuck, faDumbbell, + faSwimmer, faSkiing, faBiking, faHiking, faCampground, + + // 天气自然 + faSun, faMoon, faCloudSun, faCloudMoon, faCloudRain, faCloudShowersHeavy, + faSnowflake, faBolt, faWind, faTemperatureHigh, faTemperatureLow, + faTree, faLeaf, faSeedling, faMountain, faWater, faFire as faFireWeather, + + // 时间日期 + faCalendar, faCalendarAlt, faCalendarCheck, faCalendarTimes, faCalendarPlus, + faClock, faStopwatch, faHourglass, faHourglassHalf, faHistory, + faBusinessTime, faCalendarWeek, faCalendarDay, + + // 安全保护 + faShield, faShieldVirus, faUserShield, faLockOpen, + faUnlock, faKeyboard, faFingerprint, faEyeDropper, faMask, faHardHat, + faLifeRing, faExclamationTriangle, faInfoCircle, faQuestionCircle, + + // 文件格式 + faFileCode, faFileArchive, faFileContract, faFileInvoice, faFileSignature, + faFileDownload, faFileUpload, faFileImport, faFileExport, faFileCsv, faFileText +} from '@fortawesome/free-solid-svg-icons'; +import { useLanguage } from '@/context/LanguageContext'; + +// 图标数据定义 +interface IconCategory { + key: string; + name: string; + icons: IconDefinition[]; +} + +const iconCategories: IconCategory[] = [ + { + key: 'popular', + name: 'popular_icons', + icons: [ + faHeart, faStar, faHome, faUser, faEnvelope, faPhone, faShoppingCart, faPlay, + faMusic, faCamera, faGift, faCheck, faBookmark, faCoffee, faGamepad, faBell, + faSearch, faDownload, faUpload, faShare, faCog, faThumbsUp, faThumbsDown, + faFire, faEye, faEyeSlash, faVolumeMute, faVolumeUp, faMicrophone, faMicrophoneSlash + ] + }, + { + key: 'business', + name: 'business_icons', + icons: [ + faChartBar, faFile, faFolder, faCogs, faWrench, faRocket, faLightbulb, + faDatabase, faCode, faBug, faEdit, faCopy, faTrash, faSave, faPrint, + faBriefcase, faBuilding, faIndustry, faHandshake, faMoneyBill, faCreditCard, + faChartLine, faChartPie, faCalculator, faClipboard, faFileAlt, faFilePdf, + faFileWord, faFileExcel, faFilePowerpoint, faFileImage, faFileVideo, faFileAudio + ] + }, + { + key: 'tech', + name: 'tech_icons', + icons: [ + faCloud, faDatabase, faServer, faLaptop, faDesktop, faMobile, faTablet, + faShieldAlt, faLock, faKey, faGlobe, faWifi, + faHdd, faSdCard, faMemory, faBatteryFull, faBatteryHalf, faBatteryEmpty, + faPlug, faPowerOff, faSignal, faRss, faQrcode, + faCode, faBug, faWrench, faDownload, faUpload + ] + }, + { + key: 'social', + name: 'social_icons', + icons: [ + faUsers, faUserFriends, faUserPlus, faUserMinus, faComments, faComment, + faCommentDots, faReply, faRetweet, faHashtag, faAt, faQuoteLeft, faQuoteRight, + faPaperPlane, faInbox, faEnvelopeOpen, faEnvelopeOpenText, faAddressBook, + faIdCard, faIdBadge, faUserTag, faUserCheck, faUserTimes, + faUser, faEnvelope, faPhone, faHeart, faShare, faBell + ] + }, + { + key: 'ui', + name: 'ui_icons', + icons: [ + faPlus, faMinus, faTimes, faArrowRight, faArrowLeft, faArrowUp, faArrowDown, + faSync, faRedo, faUndo, faRefresh, faExpand, faCompress, faMaximize, faMinimize, + faAngleUp, faAngleDown, faAngleLeft, faAngleRight, faChevronUp, faChevronDown, + faChevronLeft, faChevronRight, faCaretUp, faCaretDown, faCaretLeft, faCaretRight, + faSort, faSortUp, faSortDown, faFilter, faBars, faEllipsisH, faEllipsisV, + faGripHorizontal, faGripVertical, faGripLines, faGripLinesVertical, + faSearch, faCog, faCheck + ] + }, + { + key: 'media', + name: 'media_icons', + icons: [ + faPlay, faPause, faStop, faStepForward, faStepBackward, faFastForward, faFastBackward, + faRandom, faRepeat, faVolumeDown, faVolumeOff, faHeadphones, + faVideo, faVideoSlash, faImage, faImages, faPhotoVideo, faFilm, + faCameraRetro, faRecordVinyl, faCompactDisc, faTv, faRadio, faPodcast, + faMusic, faCamera, faVolumeMute, faVolumeUp, faMicrophone, faMicrophoneSlash + ] + }, + { + key: 'transport', + name: 'transport_icons', + icons: [ + faCar, faTruck, faBus, faTaxi, faMotorcycle, faBicycle, faPlane, faTrain, + faShip, faSubway, faWalking, faRunning, faMapMarkerAlt, faMap, faRoute, + faCompass, faLocationArrow, faStreetView, faRoad, faParking, faGasPump + ] + }, + { + key: 'shopping', + name: 'shopping_icons', + icons: [ + faShoppingCart, faShoppingBag, faShoppingBasket, faStoreAlt, faStore, faReceipt, faBarcode, + faTags, faPercent, faGem, faCrown, faAward, faMedal, faTrophy, faRibbon, + faGifts, faBox, faBoxOpen, faBoxes, faWarehouse, faShippingFast, + faMoneyBill, faCreditCard, faGift + ] + }, + { + key: 'health', + name: 'health_icons', + icons: [ + faHeartSolid, faHeartbeat, faStethoscope, faUserMd, faHospital, + faAmbulance, faPills, faSyringe, faThermometer, faBandAid, faFirstAid, + faDna, faMicroscope, faXRay, faTeeth, faEyeMedical, faBrain + ] + }, + { + key: 'food', + name: 'food_icons', + icons: [ + faUtensils, faUtensilSpoon, faCocktail, faWineGlass, + faBeer, faPizzaSlice, faHamburger, faHotdog, faIceCream, faCake, + faAppleAlt, faCarrot, faCheese, faFish, faEgg, faBacon, faBreadSlice, faCoffee + ] + }, + { + key: 'sports', + name: 'sports_icons', + icons: [ + faFutbol, faBasketballBall, faBaseballBall, faFootballBall, faVolleyballBall, + faTableTennis, faGolfBall, faBowlingBall, faHockeyPuck, faDumbbell, + faSwimmer, faSkiing, faBiking, faHiking, faCampground + ] + }, + { + key: 'weather', + name: 'weather_icons', + icons: [ + faSun, faMoon, faCloudSun, faCloudMoon, faCloudRain, faCloudShowersHeavy, + faSnowflake, faBolt, faWind, faTemperatureHigh, faTemperatureLow, + faTree, faLeaf, faSeedling, faMountain, faWater, faFireWeather, faCloud + ] + }, + { + key: 'time', + name: 'time_icons', + icons: [ + faCalendar, faCalendarAlt, faCalendarCheck, faCalendarTimes, faCalendarPlus, + faClock, faStopwatch, faHourglass, faHourglassHalf, faHistory, + faBusinessTime, faCalendarWeek, faCalendarDay + ] + }, + { + key: 'security', + name: 'security_icons', + icons: [ + faShield, faShieldVirus, faUserShield, faLockOpen, + faUnlock, faKeyboard, faFingerprint, faEyeDropper, faMask, faHardHat, + faLifeRing, faExclamationTriangle, faInfoCircle, faQuestionCircle, + faShieldAlt, faLock, faKey + ] + }, + { + key: 'files', + name: 'files_icons', + icons: [ + faFileCode, faFileArchive, faFileContract, faFileInvoice, faFileSignature, + faFileDownload, faFileUpload, faFileImport, faFileExport, faFileCsv, faFileText, + faFile, faFolder, faFileAlt, faFilePdf, faFileWord, faFileExcel, + faFilePowerpoint, faFileImage, faFileVideo, faFileAudio + ] + } +]; + +// 为图标创建搜索关键词映射 +const iconKeywords: Record = { + [faHeart.iconName]: ['heart', 'love', 'like', '心', '爱心', '喜欢'], + [faStar.iconName]: ['star', 'favorite', 'rating', '星', '收藏', '评分'], + [faHome.iconName]: ['home', 'house', '家', '首页'], + [faUser.iconName]: ['user', 'person', 'profile', '用户', '人', '个人资料'], + [faEnvelope.iconName]: ['mail', 'email', 'message', '邮件', '消息'], + [faPhone.iconName]: ['phone', 'call', 'contact', '电话', '联系'], + [faShoppingCart.iconName]: ['cart', 'shop', 'buy', '购物车', '商店', '购买'], + [faPlay.iconName]: ['play', 'start', 'video', '播放', '开始', '视频'], + [faMusic.iconName]: ['music', 'audio', 'sound', '音乐', '音频', '声音'], + [faCamera.iconName]: ['camera', 'photo', 'picture', '相机', '照片', '图片'], + [faGift.iconName]: ['gift', 'present', 'reward', '礼物', '奖励'], + [faCheck.iconName]: ['check', 'ok', 'done', '检查', '确认', '完成'], + [faBookmark.iconName]: ['bookmark', 'save', 'mark', '书签', '保存', '标记'], + [faCoffee.iconName]: ['coffee', 'drink', 'cafe', '咖啡', '饮料'], + [faGamepad.iconName]: ['game', 'play', 'gaming', '游戏', '娱乐'], + [faChartBar.iconName]: ['chart', 'graph', 'analytics', '图表', '分析'], + [faFile.iconName]: ['file', 'document', 'paper', '文件', '文档'], + [faFolder.iconName]: ['folder', 'directory', '文件夹', '目录'], + [faCogs.iconName]: ['settings', 'config', 'gear', '设置', '配置'], + [faWrench.iconName]: ['tool', 'fix', 'repair', '工具', '修复'], + [faRocket.iconName]: ['rocket', 'fast', 'launch', '火箭', '快速', '启动'], + [faLightbulb.iconName]: ['idea', 'light', 'innovation', '想法', '创新'], + [faDatabase.iconName]: ['database', 'data', 'storage', '数据库', '数据'], + [faCode.iconName]: ['code', 'programming', 'developer', '代码', '编程'], + [faBug.iconName]: ['bug', 'error', 'debug', '错误', '调试'], + [faEdit.iconName]: ['edit', 'write', 'modify', '编辑', '修改'], + [faCopy.iconName]: ['copy', 'duplicate', '复制'], + [faTrash.iconName]: ['delete', 'remove', 'trash', '删除', '垃圾桶'], + [faCloud.iconName]: ['cloud', 'online', 'storage', '云', '在线'], + [faShieldAlt.iconName]: ['security', 'protect', 'safe', '安全', '保护'], + [faLock.iconName]: ['lock', 'secure', 'private', '锁', '安全', '私有'], + [faKey.iconName]: ['key', 'password', 'access', '钥匙', '密码', '访问'], + [faGlobe.iconName]: ['world', 'global', 'internet', '世界', '全球', '网络'], + [faWifi.iconName]: ['wifi', 'wireless', 'internet', '无线网络'], + [faShare.iconName]: ['share', 'send', 'forward', '分享', '发送'], + [faDownload.iconName]: ['download', 'save', '下载', '保存'], + [faUpload.iconName]: ['upload', 'send', '上传', '发送'], + [faBell.iconName]: ['notification', 'alert', 'bell', '通知', '提醒'], + [faSearch.iconName]: ['search', 'find', 'look', '搜索', '查找'], + [faCog.iconName]: ['setting', 'config', 'gear', '设置', '配置'], + [faPlus.iconName]: ['add', 'plus', 'new', '添加', '新增'], + [faMinus.iconName]: ['minus', 'remove', 'subtract', '减少', '删除'], + [faTimes.iconName]: ['close', 'cancel', 'exit', '关闭', '取消'], + [faSync.iconName]: ['refresh', 'reload', 'sync', '刷新', '同步'], + [faSave.iconName]: ['save', 'store', 'keep', '保存', '存储'], + [faPrint.iconName]: ['print', 'printer', '打印'], + [faCalendar.iconName]: ['calendar', 'date', 'schedule', '日历', '日期'], + [faClock.iconName]: ['time', 'clock', 'schedule', '时间', '时钟'], + [faMapMarkerAlt.iconName]: ['location', 'place', 'map', '位置', '地点'] +}; + +interface IconSelectorProps { + selectedIcon: IconDefinition; + onIconSelect: (icon: IconDefinition) => void; +} + +export default function IconSelector({ selectedIcon, onIconSelect }: IconSelectorProps) { + const { t } = useLanguage(); + const [searchTerm, setSearchTerm] = useState(''); + const [activeCategory, setActiveCategory] = useState('popular'); + + // 搜索过滤图标 + const filteredCategories = useMemo(() => { + if (!searchTerm.trim()) { + return iconCategories; + } + + const searchLower = searchTerm.toLowerCase(); + + return iconCategories.map(category => ({ + ...category, + icons: category.icons.filter(icon => { + const keywords = iconKeywords[icon.iconName] || []; + return keywords.some(keyword => + keyword.toLowerCase().includes(searchLower) + ) || icon.iconName.toLowerCase().includes(searchLower); + }) + })).filter(category => category.icons.length > 0); + }, [searchTerm]); + + const styles = { + container: "space-y-4", + searchInput: "search-input w-full", + categoryTabs: "flex flex-wrap gap-2 mb-4", + categoryTab: "px-3 py-1 text-sm rounded-md cursor-pointer transition-colors", + categoryTabActive: "px-3 py-1 text-sm rounded-md cursor-pointer transition-colors bg-purple-600 text-white", + categoryTabInactive: "px-3 py-1 text-sm rounded-md cursor-pointer transition-colors bg-gray-700 text-gray-300 hover:bg-gray-600", + iconGrid: "grid grid-cols-6 sm:grid-cols-8 md:grid-cols-10 gap-2", + iconButton: "btn-option p-3 flex items-center justify-center text-lg hover:scale-110 transition-transform", + iconButtonActive: "btn-option-active p-3 flex items-center justify-center text-lg scale-110", + categorySection: "mb-6", + categoryTitle: "text-sm font-medium mb-3 text-secondary", + noResults: "text-center text-gray-500 py-8" + }; + + return ( +
+ setSearchTerm(e.target.value)} + className={styles.searchInput} + /> + + {!searchTerm && ( +
+ {iconCategories.map((category) => ( + + ))} +
+ )} + + {filteredCategories.length === 0 ? ( +
+ 没有找到匹配的图标 +
+ ) : ( +
+ {searchTerm ? ( + // 搜索模式:显示所有匹配的分类 + filteredCategories.map((category) => ( +
+

+ {t(`tools.icon_designer.${category.name}`)} ({category.icons.length}) +

+
+ {category.icons.map((icon, index) => ( + + ))} +
+
+ )) + ) : ( + // 分类模式:只显示当前激活的分类 + (() => { + const currentCategory = iconCategories.find(cat => cat.key === activeCategory); + return currentCategory ? ( +
+ {currentCategory.icons.map((icon, index) => ( + + ))} +
+ ) : null; + })() + )} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/app/tools/icon_designer/page.tsx b/src/app/tools/icon_designer/page.tsx new file mode 100644 index 0000000..64a76c0 --- /dev/null +++ b/src/app/tools/icon_designer/page.tsx @@ -0,0 +1,583 @@ +'use client'; + +import React, { useState, useRef } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faCube, faDownload, faStar +} from '@fortawesome/free-solid-svg-icons'; +import ToolHeader from '@/components/ToolHeader'; +import { useLanguage } from '@/context/LanguageContext'; +import IconSelector from './components/IconSelector'; +import EnhancedIconPreview, { ShapeType, BackgroundType, IconType } from './components/EnhancedIconPreview'; +import EnhancedIconCanvas, { EnhancedIconCanvasRef } from './components/EnhancedIconCanvas'; + +// 样式定义 +const styles = { + container: "min-h-screen flex flex-col max-w-[1440px] mx-auto p-4 md:p-6", + card: "card p-6 mb-6", + section: "mb-6", + sectionTitle: "text-lg font-semibold mb-3 text-primary", + grid: "grid grid-cols-1 lg:grid-cols-3 gap-6", + leftPanel: "lg:col-span-2 space-y-6", + rightPanel: "lg:col-span-1", + iconGrid: "grid grid-cols-6 sm:grid-cols-8 md:grid-cols-10 gap-2", + iconButton: "btn-option p-3 flex items-center justify-center text-lg hover:scale-110 transition-transform", + iconButtonActive: "btn-option-active p-3 flex items-center justify-center text-lg scale-110", + shapeGrid: "grid grid-cols-2 sm:grid-cols-4 gap-2", + shapeButton: "btn-option p-4 flex flex-col items-center justify-center", + shapeButtonActive: "btn-option-active p-4 flex flex-col items-center justify-center", + colorGrid: "grid grid-cols-4 sm:grid-cols-6 gap-2", + colorButton: "w-12 h-12 rounded-lg border-2 border-white/20 hover:border-white/60 transition-all cursor-pointer", + colorButtonActive: "w-12 h-12 rounded-lg border-2 border-purple-500 scale-110 shadow-lg shadow-purple-500/30", + slider: "w-full accent-[rgb(var(--color-primary))]", + previewArea: "card p-8 flex flex-col items-center justify-center min-h-80", + previewIcon: "mb-4 transition-all duration-300", + templateGrid: "grid grid-cols-1 sm:grid-cols-2 gap-3", + templateButton: "btn-option p-4 text-left", + exportGrid: "grid grid-cols-2 gap-3", + searchInput: "search-input w-full mb-4", + iconCategory: "mb-4", + categoryTitle: "text-sm font-medium mb-2 text-secondary", + label: "block text-sm font-medium mb-2 text-secondary", + input: "w-full px-3 py-2 bg-card border border-gray-600 rounded-lg text-primary placeholder-tertiary focus:border-purple-500 focus:ring-2 focus:ring-purple-500/20 transition-all", + select: "w-full px-3 py-2 bg-card border border-gray-600 rounded-lg text-primary focus:border-purple-500 focus:ring-2 focus:ring-purple-500/20 transition-all", + colorInput: "w-12 h-10 border-0 rounded-lg cursor-pointer", +}; + +// 移除原有的图标数据,现在由IconSelector组件管理 + +// 颜色预设 +const colorPresets = [ + '#000000', '#FFFFFF', '#6B7280', '#3B82F6', '#10B981', + '#EF4444', '#F59E0B', '#8B5CF6', '#EC4899', '#14B8A6' +]; + +// ShapeType现在从IconCanvas组件导入 + +// 预设模板 +interface Template { + name: string; + backgroundType: BackgroundType; + backgroundColor: string; + gradientStartColor?: string; + gradientEndColor?: string; + gradientDirection?: number; + iconColor: string; + shape: ShapeType; + iconSize: number; + iconRotation?: number; +} + +const templates: Template[] = [ + { + name: 'iOS Style', + backgroundType: 'solid', + backgroundColor: '#000000', + iconColor: '#FFFFFF', + shape: 'rounded-square', + iconSize: 60 + }, + { + name: 'Material', + backgroundType: 'solid', + backgroundColor: '#4CAF50', + iconColor: '#FFFFFF', + shape: 'circle', + iconSize: 55 + }, + { + name: 'Minimal', + backgroundType: 'solid', + backgroundColor: '#FFFFFF', + iconColor: '#000000', + shape: 'square', + iconSize: 50 + }, + { + name: 'Gradient', + backgroundType: 'linear-gradient', + backgroundColor: '#8B5CF6', + gradientStartColor: '#6366F1', + gradientEndColor: '#8B5CF6', + gradientDirection: 45, + iconColor: '#FFFFFF', + shape: 'rounded-square', + iconSize: 65 + }, + { + name: 'Neon', + backgroundType: 'radial-gradient', + backgroundColor: '#000000', + gradientStartColor: '#FF006E', + gradientEndColor: '#8338EC', + iconColor: '#FFFFFF', + shape: 'circle', + iconSize: 70, + iconRotation: 15 + }, + { + name: 'Retro', + backgroundType: 'linear-gradient', + backgroundColor: '#F72585', + gradientStartColor: '#F72585', + gradientEndColor: '#B5179E', + gradientDirection: 135, + iconColor: '#FFE66D', + shape: 'square', + iconSize: 65 + }, + { + name: 'Glassmorphism', + backgroundType: 'linear-gradient', + backgroundColor: 'rgba(255,255,255,0.1)', + gradientStartColor: 'rgba(255,255,255,0.2)', + gradientEndColor: 'rgba(255,255,255,0.05)', + iconColor: '#FFFFFF', + shape: 'rounded-square', + iconSize: 60 + }, + { + name: 'Neumorphism', + backgroundType: 'solid', + backgroundColor: '#E0E5EC', + iconColor: '#9BAACF', + shape: 'rounded-square', + iconSize: 55 + } +]; + +export default function IconDesigner() { + const { t } = useLanguage(); + const canvasRef = useRef(null); + + // 图标相关状态 + const [iconType, setIconType] = useState('fontawesome'); + const [selectedIcon, setSelectedIcon] = useState(faStar); + const [customText, setCustomText] = useState('ABC'); + const [iconColor, setIconColor] = useState('#FFFFFF'); + const [iconSize, setIconSize] = useState(60); + const [iconRotation, setIconRotation] = useState(0); + const [fontFamily, setFontFamily] = useState('Arial, sans-serif'); + const [fontWeight, setFontWeight] = useState('bold'); + const [fontSize, setFontSize] = useState(40); // 独立的字体大小,用于文字模式 + + // 背景相关状态 + const [backgroundType, setBackgroundType] = useState('solid'); + const [backgroundColor, setBackgroundColor] = useState('#000000'); + const [gradientStartColor, setGradientStartColor] = useState('#6366F1'); + const [gradientEndColor, setGradientEndColor] = useState('#8B5CF6'); + const [gradientDirection, setGradientDirection] = useState(45); + const [shape, setShape] = useState('rounded-square'); + + // 导出相关状态 + const [exportSize, setExportSize] = useState(256); + const [exportFormat, setExportFormat] = useState('png'); + const [isGenerating, setIsGenerating] = useState(false); + + // 应用模板 + const applyTemplate = (template: Template) => { + setBackgroundType(template.backgroundType); + setBackgroundColor(template.backgroundColor); + if (template.gradientStartColor) setGradientStartColor(template.gradientStartColor); + if (template.gradientEndColor) setGradientEndColor(template.gradientEndColor); + if (template.gradientDirection) setGradientDirection(template.gradientDirection); + setIconColor(template.iconColor); + setShape(template.shape); + setIconSize(template.iconSize); + if (template.iconRotation) setIconRotation(template.iconRotation); + }; + + + + // 下载图标 + const downloadIcon = async () => { + if (!canvasRef.current) return; + + setIsGenerating(true); + + try { + const dataUrl = await canvasRef.current.generateIcon(exportSize); + + // 下载 + const link = document.createElement('a'); + link.download = `icon-${Date.now()}.${exportFormat}`; + link.href = dataUrl; + link.click(); + } catch (error) { + console.error('下载失败:', error); + } finally { + setIsGenerating(false); + } + }; + + return ( +
+ + +
+ {/* 左侧控制面板 */} +
+ {/* 图标选择 */} +
+

{t('tools.icon_designer.icon_selection')}

+ + {/* 图标类型选择 */} +
+ +
+ + +
+
+ + {/* FontAwesome图标选择器 */} + {iconType === 'fontawesome' && ( + + )} + + {/* 自定义文字输入 */} + {iconType === 'text' && ( +
+
+ + setCustomText(e.target.value)} + placeholder={t('tools.icon_designer.text_input_placeholder')} + className={styles.input} + maxLength={10} + /> +
+
+ + +
+
+ + +
+
+ + setFontSize(Number(e.target.value))} + className={styles.slider} + /> +
+
+ )} +
+ + {/* 图标设置 */} +
+

{t('tools.icon_designer.icon_settings')}

+ +
+ +
+ {colorPresets.map((color) => ( +
+ setIconColor(e.target.value)} + className="mt-2 w-full h-10 rounded border-0 cursor-pointer" + /> +
+ + {iconType === 'fontawesome' && ( +
+ + setIconSize(Number(e.target.value))} + className={styles.slider} + /> +
+ )} + +
+ + setIconRotation(Number(e.target.value))} + className={styles.slider} + /> +
+
+ + {/* 背景设置 */} +
+

{t('tools.icon_designer.background_settings')}

+ +
+ +
+ {(['circle', 'square', 'rounded-square', 'hexagon'] as ShapeType[]).map((shapeType) => ( + + ))} +
+
+ +
+ +
+ {colorPresets.map((color) => ( +
+ setBackgroundColor(e.target.value)} + className="mt-2 w-full h-10 rounded border-0 cursor-pointer" + /> +
+
+ + {/* 预设模板 */} +
+

{t('tools.icon_designer.preset_templates')}

+
+ {templates.map((template, index) => ( + + ))} +
+
+
+ + {/* 右侧预览和导出 */} +
+ {/* 预览 */} +
+

{t('tools.icon_designer.preview')}

+
+ + + {/* 隐藏的Canvas用于导出 */} +
+ +
+
+
+ + {/* 导出设置 */} +
+

{t('tools.icon_designer.export_settings')}

+ +
+ +
+ {[64, 128, 256, 512].map((size) => ( + + ))} +
+
+ +
+ +
+ {['png', 'svg'].map((format) => ( + + ))} +
+
+ + +
+ + {/* 使用说明 */} +
+

+ {t('tools.icon_designer.usage_guide')} +

+
    +
  • {t('tools.icon_designer.guide_1')}
  • +
  • {t('tools.icon_designer.guide_2')}
  • +
  • {t('tools.icon_designer.guide_3')}
  • +
  • {t('tools.icon_designer.guide_4')}
  • +
  • {t('tools.icon_designer.guide_5')}
  • +
  • {t('tools.icon_designer.guide_6')}
  • +
+ +
+

{t('tools.icon_designer.tips')}

+
    +
  • {t('tools.icon_designer.tip_1')}
  • +
  • {t('tools.icon_designer.tip_2')}
  • +
  • {t('tools.icon_designer.tip_3')}
  • +
  • {t('tools.icon_designer.tip_4')}
  • +
  • {t('tools.icon_designer.tip_5')}
  • +
  • {t('tools.icon_designer.tip_6')}
  • +
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/config/i18n/en.ts b/src/config/i18n/en.ts index 12b16b4..18d465f 100644 --- a/src/config/i18n/en.ts +++ b/src/config/i18n/en.ts @@ -31,7 +31,8 @@ export const en = { base64_to_image: tools.base64_to_image.en, image_watermark: tools.image_watermark.en, image_to_ico: tools.image_to_ico.en, - cron_generator: tools.cron_generator.en + cron_generator: tools.cron_generator.en, + icon_designer: tools.icon_designer.en } }; diff --git a/src/config/i18n/tools/icon_designer/en.ts b/src/config/i18n/tools/icon_designer/en.ts new file mode 100644 index 0000000..6e38bba --- /dev/null +++ b/src/config/i18n/tools/icon_designer/en.ts @@ -0,0 +1,111 @@ +export const iconDesignerEn = { + title: 'Icon Designer', + description: 'Quickly design clean and beautiful app icons with various background shapes and color combinations', + icon_selection: 'Icon Selection', + choose_icon: 'Choose Icon', + icon_search_placeholder: 'Search icons...', + popular_icons: 'Popular Icons', + business_icons: 'Business Icons', + tech_icons: 'Tech Icons', + social_icons: 'Social Icons', + ui_icons: 'UI Icons', + media_icons: 'Media Icons', + transport_icons: 'Transport Icons', + shopping_icons: 'Shopping Icons', + health_icons: 'Health Icons', + food_icons: 'Food Icons', + sports_icons: 'Sports Icons', + weather_icons: 'Weather Icons', + time_icons: 'Time Icons', + security_icons: 'Security Icons', + files_icons: 'File Icons', + + background_settings: 'Background Settings', + background_shape: 'Background Shape', + background_color: 'Background Color', + background_type: 'Background Type', + background_solid: 'Solid', + background_gradient: 'Gradient', + gradient_direction: 'Gradient Direction', + gradient_start: 'Start Color', + gradient_end: 'End Color', + gradient_linear: 'Linear Gradient', + gradient_radial: 'Radial Gradient', + + shape_circle: 'Circle', + shape_square: 'Square', + shape_rounded_square: 'Rounded Square', + shape_hexagon: 'Hexagon', + + icon_settings: 'Icon Settings', + icon_type: 'Icon Type', + icon_type_fontawesome: 'FontAwesome Icon', + icon_type_text: 'Custom Text', + icon_color: 'Icon Color', + icon_size: 'Icon Size', + icon_position: 'Icon Position', + icon_rotation: 'Icon Rotation', + text_input: 'Enter Text', + text_input_placeholder: 'Enter your text...', + font_family: 'Font Family', + font_weight: 'Font Weight', + font_size: 'Font Size', + + color_black: 'Black', + color_white: 'White', + color_gray: 'Gray', + color_blue: 'Blue', + color_green: 'Green', + color_red: 'Red', + color_orange: 'Orange', + color_purple: 'Purple', + color_custom: 'Custom', + + preset_templates: 'Preset Templates', + template_ios_style: 'iOS Style', + template_material: 'Material Style', + template_minimal: 'Minimal Style', + template_gradient: 'Gradient Style', + template_neon: 'Neon Style', + template_retro: 'Retro Style', + template_glassmorphism: 'Glassmorphism', + template_neumorphism: 'Neumorphism', + + export_settings: 'Export Settings', + export_size: 'Export Size', + export_format: 'Export Format', + download_icon: 'Download Icon', + + size_small: 'Small (64x64)', + size_medium: 'Medium (128x128)', + size_large: 'Large (256x256)', + size_xlarge: 'X-Large (512x512)', + + format_png: 'PNG Format', + format_svg: 'SVG Format', + format_ico: 'ICO Format', + + preview: 'Preview', + no_icon_selected: 'No Icon Selected', + select_icon_first: 'Please select an icon first', + + usage_guide: 'Usage Guide', + guide_1: '1. Choose icon type: FontAwesome icon or custom text', + guide_2: '2. Configure icon content, color, size and rotation', + guide_3: '3. Select background shape and type (solid or gradient)', + guide_4: '4. Adjust background color or gradient settings', + guide_5: '5. Apply preset templates for quick design', + guide_6: '6. Select export size and format, then download', + + tips: 'Tips', + tip_1: 'Recommend using high contrast color combinations, like black background with white icon', + tip_2: 'For mobile apps, rounded square background is recommended', + tip_3: 'Gradient backgrounds can add depth and modern feel to icons', + tip_4: 'Custom text feature supports creating brand initials or short word icons', + tip_5: 'Appropriate rotation angles can add dynamic feel to icons', + tip_6: 'Neumorphism and glassmorphism templates suit modern UI design', + + applying_template: 'Applying template...', + generating_icon: 'Generating icon...', + download_ready: 'Download ready' +}; \ No newline at end of file diff --git a/src/config/i18n/tools/icon_designer/index.ts b/src/config/i18n/tools/icon_designer/index.ts new file mode 100644 index 0000000..28b0a9d --- /dev/null +++ b/src/config/i18n/tools/icon_designer/index.ts @@ -0,0 +1,7 @@ +import { iconDesignerZh } from './zh'; +import { iconDesignerEn } from './en'; + +export const iconDesigner = { + zh: iconDesignerZh, + en: iconDesignerEn +}; \ No newline at end of file diff --git a/src/config/i18n/tools/icon_designer/zh.ts b/src/config/i18n/tools/icon_designer/zh.ts new file mode 100644 index 0000000..76d58c2 --- /dev/null +++ b/src/config/i18n/tools/icon_designer/zh.ts @@ -0,0 +1,111 @@ +export const iconDesignerZh = { + title: '图标设计器', + description: '快速设计简洁精美的应用图标,支持多种形状背景和颜色搭配', + icon_selection: '图标选择', + choose_icon: '选择图标', + icon_search_placeholder: '搜索图标...', + popular_icons: '常用图标', + business_icons: '商务图标', + tech_icons: '科技图标', + social_icons: '社交图标', + ui_icons: '界面图标', + media_icons: '媒体图标', + transport_icons: '交通出行', + shopping_icons: '购物电商', + health_icons: '健康医疗', + food_icons: '食物饮料', + sports_icons: '运动休闲', + weather_icons: '天气自然', + time_icons: '时间日期', + security_icons: '安全保护', + files_icons: '文件格式', + + background_settings: '背景设置', + background_shape: '背景形状', + background_color: '背景颜色', + background_type: '背景类型', + background_solid: '纯色', + background_gradient: '渐变', + gradient_direction: '渐变方向', + gradient_start: '起始颜色', + gradient_end: '结束颜色', + gradient_linear: '线性渐变', + gradient_radial: '径向渐变', + + shape_circle: '圆形', + shape_square: '正方形', + shape_rounded_square: '圆角正方形', + shape_hexagon: '六边形', + + icon_settings: '图标设置', + icon_type: '图标类型', + icon_type_fontawesome: 'FontAwesome图标', + icon_type_text: '自定义文字', + icon_color: '图标颜色', + icon_size: '图标大小', + icon_position: '图标位置', + icon_rotation: '图标旋转', + text_input: '输入文字', + text_input_placeholder: '输入您的文字...', + font_family: '字体', + font_weight: '字体粗细', + font_size: '字体大小', + + color_black: '黑色', + color_white: '白色', + color_gray: '灰色', + color_blue: '蓝色', + color_green: '绿色', + color_red: '红色', + color_orange: '橙色', + color_purple: '紫色', + color_custom: '自定义', + + preset_templates: '预设模板', + template_ios_style: 'iOS风格', + template_material: 'Material风格', + template_minimal: '极简风格', + template_gradient: '渐变风格', + template_neon: '霓虹风格', + template_retro: '复古风格', + template_glassmorphism: '玻璃拟态', + template_neumorphism: '新拟态', + + export_settings: '导出设置', + export_size: '导出尺寸', + export_format: '导出格式', + download_icon: '下载图标', + + size_small: '小 (64x64)', + size_medium: '中 (128x128)', + size_large: '大 (256x256)', + size_xlarge: '超大 (512x512)', + + format_png: 'PNG格式', + format_svg: 'SVG格式', + format_ico: 'ICO格式', + + preview: '预览', + no_icon_selected: '未选择图标', + select_icon_first: '请先选择一个图标', + + usage_guide: '使用说明', + guide_1: '1. 选择图标类型:FontAwesome图标或自定义文字', + guide_2: '2. 配置图标内容、颜色、大小和旋转', + guide_3: '3. 选择背景形状和类型(纯色或渐变)', + guide_4: '4. 调整背景颜色或渐变设置', + guide_5: '5. 应用预设模板快速设计', + guide_6: '6. 选择导出尺寸和格式并下载', + + tips: '小贴士', + tip_1: '建议使用高对比度的颜色搭配,如黑底白图标或白底黑图标', + tip_2: '对于移动应用,推荐使用圆角正方形背景', + tip_3: '渐变背景可以让图标更有层次感和现代感', + tip_4: '自定义文字功能支持创建品牌首字母或简短词汇图标', + tip_5: '适当的旋转角度可以增加图标的动感', + tip_6: '新拟态和玻璃拟态模板适合现代UI设计', + + applying_template: '正在应用模板...', + generating_icon: '正在生成图标...', + download_ready: '下载就绪' +}; \ No newline at end of file diff --git a/src/config/i18n/tools/index.ts b/src/config/i18n/tools/index.ts index 4f31559..414e588 100644 --- a/src/config/i18n/tools/index.ts +++ b/src/config/i18n/tools/index.ts @@ -26,6 +26,7 @@ import base64ToImage from './base64_to_image'; import imageWatermark from './image_watermark'; import imageToIco from './image_to_ico'; import cronGenerator from './cron_generator'; +import { iconDesigner } from './icon_designer'; export const tools = { json_formatter: jsonFormatter, @@ -55,7 +56,8 @@ export const tools = { base64_to_image: base64ToImage, image_watermark: imageWatermark, image_to_ico: imageToIco, - cron_generator: cronGenerator + cron_generator: cronGenerator, + icon_designer: iconDesigner }; export default tools; diff --git a/src/config/i18n/zh.ts b/src/config/i18n/zh.ts index 5dcff97..55cde70 100644 --- a/src/config/i18n/zh.ts +++ b/src/config/i18n/zh.ts @@ -31,7 +31,8 @@ export const zh = { base64_to_image: tools.base64_to_image.zh, image_watermark: tools.image_watermark.zh, image_to_ico: tools.image_to_ico.zh, - cron_generator: tools.cron_generator.zh + cron_generator: tools.cron_generator.zh, + icon_designer: tools.icon_designer.zh } }; diff --git a/src/config/tools.ts b/src/config/tools.ts index 29df341..22ebc20 100644 --- a/src/config/tools.ts +++ b/src/config/tools.ts @@ -2,7 +2,7 @@ import { faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock, faImage, faCogs, faFileCode, faKey, faFont, faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired, - faEraser, faCalculator, faFileAlt + faEraser, faCalculator, faFileAlt, faCube } from '@fortawesome/free-solid-svg-icons'; import { Tool } from '@/types/tools'; @@ -166,17 +166,17 @@ const tools: Tool[] = [ category: ['image'], keywords: ['图片水印', '水印', '水印添加', '图片', '文字水印', '图片水印', 'watermark', 'image watermark', 'tupian shuiyin', 'tpshuiyin', 'shuiyin', 'sy', 'tp'] }, - { - code: 'image_to_ico', - icon: faImage, - category: ['image'], - keywords: ['图标', 'ico', '图片转ico', 'icon', '图标生成', '图标转换', 'favicon', '网站图标', 'tubiao', 'tb', 'zhuanicon', 'icon转换', 'icon生成'] - }, { code: 'cron_generator', icon: faCalendarAlt, category: ['datetime'], keywords: ['cron', 'cron表达式', '定时任务', '调度', '表达式生成', '执行时间', 'crontab', 'quartz', 'schedule', 'dingshi', 'dingshibiaodashi', 'dsrw', 'bds', 'cronbds'] + }, + { + code: 'icon_designer', + icon: faCube, + category: ['common', 'image'], + keywords: ['图标设计', '图标生成', 'icon设计', '图标制作', 'app图标', 'logo设计', 'favicon制作', '图标工具', 'icon designer', 'icon generator', 'tubiao', 'tb', 'sheji', 'sj', 'zhizuo', 'zz'] } ] as Tool[];