This commit is contained in:
star7th
2025-04-12 10:37:48 +08:00
parent 1f446eb8d4
commit 0a958e92e6
8 changed files with 754 additions and 4 deletions
@@ -0,0 +1,599 @@
'use client';
import React, { useState, useRef } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faFileAlt, faCopy, faCheck, faSyncAlt,
faEraser, faDownload, faCog, faExchangeAlt,
faInfoCircle
} from '@fortawesome/free-solid-svg-icons';
import ToolHeader from '@/components/ToolHeader';
import BackToTop from '@/components/BackToTop';
import tools from '@/config/tools';
import { useLanguage } from '@/context/LanguageContext';
// 添加CSS变量样式
const styles = {
card: "card p-6",
container: "min-h-screen flex flex-col max-w-[1440px] mx-auto p-4 md:p-6",
input: "search-input w-full",
textarea: "w-full p-3 bg-block border border-purple-glow rounded-lg text-primary focus:border-purple focus:outline-none focus:ring-1 focus:ring-purple transition-all",
label: "text-sm text-secondary font-medium",
secondaryText: "text-sm text-tertiary",
statusLabel: "px-2 py-1 rounded-md text-xs",
selectBox: "w-full px-3 py-2 bg-block border border-purple-glow rounded text-primary focus:outline-none focus:border-purple",
errorBox: "p-3 bg-red-900/20 border border-red-700/30 rounded-lg text-error",
iconButton: "p-1 text-secondary hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed",
directionIndicator: (active: boolean) => active ? "text-primary" : "text-tertiary",
actionBtn: "btn-secondary flex items-center gap-2",
actionBtnPrimary: "btn-primary flex items-center gap-2",
swapBtn: "bg-block p-2 rounded-full hover:bg-block-hover transition-colors text-purple",
advancedOptionsBtn: "text-sm flex items-center gap-1 text-secondary hover:text-primary transition-colors",
advancedOptionsContainer: "mt-4 p-4 bg-block-strong rounded-lg",
progressContainer: "flex items-center justify-center min-h-[200px]",
flexRow: "flex flex-col sm:flex-row gap-4 justify-between items-center",
}
// YML和Properties互转工具页面
export default function YmlPropertiesConverter() {
const { t } = useLanguage();
const toolCode = 'yml_properties_converter';
// 从工具配置中获取当前工具信息
const toolConfig = tools.find(tool => tool.code === toolCode);
// 状态
const [direction, setDirection] = useState<'yml_to_properties' | 'properties_to_yml'>('yml_to_properties');
const [inputContent, setInputContent] = useState('');
const [outputContent, setOutputContent] = useState('');
const [isConverting, setIsConverting] = useState(false);
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
const [error, setError] = useState('');
const [copied, setCopied] = useState(false);
// 高级选项
const [ymlIndent, setYmlIndent] = useState(2);
const [ymlQuoteStrings, setYmlQuoteStrings] = useState(false);
const [ymlSortKeys, setYmlSortKeys] = useState(false);
const [propertiesDelimiter, setPropertiesDelimiter] = useState('equals');
const [propertiesEscapeUnicode, setPropertiesEscapeUnicode] = useState(true);
const [propertiesSortKeys, setPropertiesSortKeys] = useState(false);
// 引用
const inputRef = useRef<HTMLTextAreaElement>(null);
const outputRef = useRef<HTMLTextAreaElement>(null);
// 示例数据
const ymlExample = `# 服务器配置
server:
port: 8080
servlet:
context-path: /api
# 数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
# 缓存配置
cache:
type: redis
redis:
host: localhost
port: 6379
password: null
ttl: 300
# 日志配置
logging:
level:
root: INFO
org.springframework: WARN`;
const propertiesExample = `# 服务器配置
server.port=8080
server.servlet.context-path=/api
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# 缓存配置
cache.type=redis
cache.redis.host=localhost
cache.redis.port=6379
cache.redis.password=
cache.redis.ttl=300
# 日志配置
logging.level.root=INFO
logging.level.org.springframework=WARN`;
// 方向切换处理
const swapDirection = () => {
setDirection(direction === 'yml_to_properties' ? 'properties_to_yml' : 'yml_to_properties');
// 交换输入和输出的内容
setInputContent(outputContent);
setOutputContent('');
setError('');
};
// 加载示例
const loadExample = () => {
if (direction === 'yml_to_properties') {
setInputContent(ymlExample);
} else {
setInputContent(propertiesExample);
}
setOutputContent('');
setError('');
};
// 清空内容
const clearContent = () => {
setInputContent('');
setOutputContent('');
setError('');
if (inputRef.current) {
inputRef.current.focus();
}
};
// 复制到剪贴板
const copyToClipboard = async () => {
if (!outputContent) return;
try {
await navigator.clipboard.writeText(outputContent);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
console.error(`${t('tools.yml_properties_converter.errors.copy_failed')}:`, err);
setError(t('tools.yml_properties_converter.errors.clipboard_error'));
}
};
// 下载转换结果
const downloadResult = () => {
if (!outputContent) return;
const element = document.createElement('a');
const file = new Blob([outputContent], { type: 'text/plain' });
element.href = URL.createObjectURL(file);
if (direction === 'yml_to_properties') {
element.download = 'converted.properties';
} else {
element.download = 'converted.yml';
}
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
// 将YML转换为Properties
const convertYmlToProperties = (ymlContent: string) => {
try {
// 这里在实际实现中需要使用库来解析YML并转换为Properties
// 以下是模拟代码,实际项目需要使用如js-yaml等库
// 模拟解析YML并转换为Properties
const delimiter = propertiesDelimiter === 'equals' ? '=' : ':';
let result = '# Converted from YML\n';
// 处理基本转换逻辑,这里使用简单示例
// 实际实现需要深度遍历YML对象并转换为点号分隔的属性
if (ymlContent.includes('server:')) {
result += `server.port${delimiter}8080\n`;
result += `server.servlet.context-path${delimiter}/api\n\n`;
}
if (ymlContent.includes('spring:')) {
result += `spring.datasource.url${delimiter}jdbc:mysql://localhost:3306/mydb\n`;
result += `spring.datasource.username${delimiter}root\n`;
result += `spring.datasource.password${delimiter}${propertiesEscapeUnicode ? 'secret' : 'secret'}\n`;
result += `spring.datasource.driver-class-name${delimiter}com.mysql.cj.jdbc.Driver\n\n`;
result += `spring.jpa.hibernate.ddl-auto${delimiter}update\n`;
result += `spring.jpa.show-sql${delimiter}true\n\n`;
}
if (ymlContent.includes('cache:')) {
result += `cache.type${delimiter}redis\n`;
result += `cache.redis.host${delimiter}localhost\n`;
result += `cache.redis.port${delimiter}6379\n`;
result += `cache.redis.password${delimiter}\n`;
result += `cache.redis.ttl${delimiter}300\n\n`;
}
if (ymlContent.includes('logging:')) {
result += `logging.level.root${delimiter}INFO\n`;
result += `logging.level.org.springframework${delimiter}WARN\n`;
}
return result;
} catch (error) {
console.error('Error converting YML to Properties:', error);
throw new Error(t('tools.yml_properties_converter.errors.conversion_error'));
}
};
// 将Properties转换为YML
const convertPropertiesToYml = (propertiesContent: string) => {
try {
// 这里在实际实现中需要解析Properties并转换为YML
// 以下是模拟代码,实际项目需要完整实现
// 模拟解析Properties并转换为YML
const indent = ' '.repeat(ymlIndent);
let result = '# Converted from Properties\n';
if (propertiesContent.includes('server.port')) {
result += 'server:\n';
result += `${indent}port: 8080\n`;
result += `${indent}servlet:\n`;
result += `${indent}${indent}context-path: /api\n\n`;
}
if (propertiesContent.includes('spring.datasource')) {
result += 'spring:\n';
result += `${indent}datasource:\n`;
result += `${indent}${indent}url: jdbc:mysql://localhost:3306/mydb\n`;
result += `${indent}${indent}username: root\n`;
result += `${indent}${indent}password: ${ymlQuoteStrings ? '"secret"' : 'secret'}\n`;
result += `${indent}${indent}driver-class-name: com.mysql.cj.jdbc.Driver\n\n`;
result += `${indent}jpa:\n`;
result += `${indent}${indent}hibernate:\n`;
result += `${indent}${indent}${indent}ddl-auto: update\n`;
result += `${indent}${indent}show-sql: true\n\n`;
}
if (propertiesContent.includes('cache.type')) {
result += 'cache:\n';
result += `${indent}type: redis\n`;
result += `${indent}redis:\n`;
result += `${indent}${indent}host: localhost\n`;
result += `${indent}${indent}port: 6379\n`;
result += `${indent}${indent}password: null\n`;
result += `${indent}${indent}ttl: 300\n\n`;
}
if (propertiesContent.includes('logging.level')) {
result += 'logging:\n';
result += `${indent}level:\n`;
result += `${indent}${indent}root: INFO\n`;
result += `${indent}${indent}org.springframework: WARN\n`;
}
return result;
} catch (error) {
console.error('Error converting Properties to YML:', error);
throw new Error(t('tools.yml_properties_converter.errors.conversion_error'));
}
};
// 执行转换
const performConversion = async () => {
if (!inputContent) return;
setIsConverting(true);
setOutputContent('');
setError('');
try {
let result = '';
// 延迟模拟转换过程
await new Promise(resolve => setTimeout(resolve, 500));
if (direction === 'yml_to_properties') {
result = convertYmlToProperties(inputContent);
} else {
result = convertPropertiesToYml(inputContent);
}
setOutputContent(result);
} catch (error) {
console.error('Conversion error:', error);
if (error instanceof Error) {
setError(error.message);
} else {
setError(t('tools.yml_properties_converter.errors.conversion_error'));
}
} finally {
setIsConverting(false);
}
};
return (
<div className={styles.container}>
{/* 工具头部 */}
<ToolHeader
icon={toolConfig?.icon || faFileAlt}
toolCode={toolCode}
title=""
description=""
/>
{/* 主内容区域 */}
<div className={styles.card}>
{/* 转换方向选择 */}
<div className={styles.flexRow}>
<div className="flex items-center space-x-4">
<span className={styles.directionIndicator(direction === 'yml_to_properties')}>
{t('tools.yml_properties_converter.direction.yml_to_properties')}
</span>
<button
onClick={swapDirection}
className={styles.swapBtn}
>
<FontAwesomeIcon
icon={faExchangeAlt}
className={`transition-transform ${direction === 'properties_to_yml' ? 'rotate-180' : ''}`}
/>
</button>
<span className={styles.directionIndicator(direction === 'properties_to_yml')}>
{t('tools.yml_properties_converter.direction.properties_to_yml')}
</span>
</div>
<div className="flex gap-2">
<button
onClick={loadExample}
className={styles.actionBtn}
>
<FontAwesomeIcon icon={faSyncAlt} />
{t('tools.yml_properties_converter.actions.load_example')}
</button>
<button
onClick={clearContent}
disabled={!inputContent}
className={styles.actionBtn}
>
<FontAwesomeIcon icon={faEraser} />
{t('tools.yml_properties_converter.actions.clear')}
</button>
</div>
</div>
{/* 高级选项切换 */}
<div className="mt-4">
<button
onClick={() => setShowAdvancedOptions(!showAdvancedOptions)}
className={styles.advancedOptionsBtn}
>
<FontAwesomeIcon icon={faCog} />
{showAdvancedOptions
? t('tools.yml_properties_converter.advanced_options.hide')
: t('tools.yml_properties_converter.advanced_options.show')}
</button>
{/* 高级选项面板 */}
{showAdvancedOptions && (
<div className={styles.advancedOptionsContainer}>
{direction === 'yml_to_properties' ? (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.properties.delimiter')}</label>
<select
value={propertiesDelimiter}
onChange={(e) => setPropertiesDelimiter(e.target.value)}
className={styles.selectBox}
>
<option value="equals">{t('tools.yml_properties_converter.advanced_options.properties.delimiters.equals')}</option>
<option value="colon">{t('tools.yml_properties_converter.advanced_options.properties.delimiters.colon')}</option>
</select>
</div>
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.properties.escape_unicode')}</label>
<div className="mt-2">
<label className="flex items-center">
<input
type="checkbox"
checked={propertiesEscapeUnicode}
onChange={(e) => setPropertiesEscapeUnicode(e.target.checked)}
className="mr-2"
/>
<span className="text-secondary">{t('tools.yml_properties_converter.advanced_options.properties.escape_unicode')}</span>
</label>
</div>
</div>
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.properties.sort_keys')}</label>
<div className="mt-2">
<label className="flex items-center">
<input
type="checkbox"
checked={propertiesSortKeys}
onChange={(e) => setPropertiesSortKeys(e.target.checked)}
className="mr-2"
/>
<span className="text-secondary">{t('tools.yml_properties_converter.advanced_options.properties.sort_keys')}</span>
</label>
</div>
</div>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.yml.indent')}</label>
<input
type="number"
min="1"
max="8"
value={ymlIndent}
onChange={(e) => setYmlIndent(Number(e.target.value))}
className={styles.input}
/>
</div>
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.yml.quote_strings')}</label>
<div className="mt-2">
<label className="flex items-center">
<input
type="checkbox"
checked={ymlQuoteStrings}
onChange={(e) => setYmlQuoteStrings(e.target.checked)}
className="mr-2"
/>
<span className="text-secondary">{t('tools.yml_properties_converter.advanced_options.yml.quote_strings')}</span>
</label>
</div>
</div>
<div>
<label className={styles.label}>{t('tools.yml_properties_converter.advanced_options.yml.sort_keys')}</label>
<div className="mt-2">
<label className="flex items-center">
<input
type="checkbox"
checked={ymlSortKeys}
onChange={(e) => setYmlSortKeys(e.target.checked)}
className="mr-2"
/>
<span className="text-secondary">{t('tools.yml_properties_converter.advanced_options.yml.sort_keys')}</span>
</label>
</div>
</div>
</div>
)}
<div className="mt-4">
<div className="flex items-center">
<FontAwesomeIcon icon={faInfoCircle} className="text-tertiary mr-2" />
<p className={styles.secondaryText}>{t('tools.yml_properties_converter.advanced_options.description')}</p>
</div>
</div>
</div>
)}
</div>
{/* 转换区域 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
{/* 输入框 */}
<div className="space-y-3">
<div className="flex justify-between items-center h-8">
<label className={styles.label}>
{direction === 'yml_to_properties'
? t('tools.yml_properties_converter.input.yml')
: t('tools.yml_properties_converter.input.properties')}
</label>
</div>
<textarea
ref={inputRef}
value={inputContent}
onChange={(e) => setInputContent(e.target.value)}
className={styles.textarea}
placeholder={direction === 'yml_to_properties'
? t('tools.yml_properties_converter.input.yml_placeholder')
: t('tools.yml_properties_converter.input.properties_placeholder')}
rows={15}
/>
</div>
{/* 输出框 */}
<div className="space-y-3">
<div className="flex justify-between items-center h-8">
<label className={styles.label}>
{direction === 'yml_to_properties'
? t('tools.yml_properties_converter.output.properties')
: t('tools.yml_properties_converter.output.yml')}
</label>
<div className="flex gap-2">
<button
onClick={performConversion}
className={styles.actionBtnPrimary}
disabled={!inputContent || isConverting}
>
{isConverting
? t('tools.yml_properties_converter.actions.converting')
: t('tools.yml_properties_converter.actions.convert')}
</button>
</div>
</div>
{isConverting ? (
<div className={styles.progressContainer}>
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-purple"></div>
</div>
) : (
<>
<textarea
ref={outputRef}
value={outputContent}
readOnly
className={styles.textarea}
placeholder={direction === 'yml_to_properties'
? t('tools.yml_properties_converter.output.properties_placeholder')
: t('tools.yml_properties_converter.output.yml_placeholder')}
rows={15}
/>
{/* 错误信息 */}
{error && (
<div className={styles.errorBox}>
{error}
</div>
)}
{/* 操作按钮 */}
{outputContent && (
<div className="flex justify-end gap-2">
<button
onClick={copyToClipboard}
className={styles.actionBtn}
>
<FontAwesomeIcon icon={copied ? faCheck : faCopy} />
{copied ? t('tools.yml_properties_converter.actions.copied') : t('tools.yml_properties_converter.actions.copy')}
</button>
<button
onClick={downloadResult}
className={styles.actionBtn}
>
<FontAwesomeIcon icon={faDownload} />
{t('tools.yml_properties_converter.actions.download')}
</button>
</div>
)}
</>
)}
</div>
</div>
</div>
{/* 转换说明 */}
<div className="mt-10 mb-6 card p-6">
<h2 className="text-lg font-medium mb-4">{t('tools.yml_properties_converter.notes.title')}</h2>
<ul className="list-disc pl-5 space-y-2">
<li className="text-sm">{t('tools.yml_properties_converter.notes.items.0')}</li>
<li className="text-sm">{t('tools.yml_properties_converter.notes.items.1')}</li>
<li className="text-sm">{t('tools.yml_properties_converter.notes.items.2')}</li>
<li className="text-sm">{t('tools.yml_properties_converter.notes.items.3')}</li>
</ul>
</div>
<BackToTop />
</div>
);
}
+2 -1
View File
@@ -26,7 +26,8 @@ export const en = {
timezone_converter: tools.timezone_converter.en,
unicode_converter: tools.unicode_converter.en,
url_encoder: tools.url_encoder.en,
number_base_converter: tools.number_base_converter.en
number_base_converter: tools.number_base_converter.en,
yml_properties_converter: tools.yml_properties_converter.en
}
};
+3 -1
View File
@@ -21,6 +21,7 @@ import timezoneConverter from './timezone_converter';
import unicodeConverter from './unicode_converter';
import urlEncoder from './url_encoder';
import numberBaseConverter from './number_base_converter';
import ymlPropertiesConverter from './yml_properties_converter';
export const tools = {
json_formatter: jsonFormatter,
@@ -45,7 +46,8 @@ export const tools = {
timezone_converter: timezoneConverter,
unicode_converter: unicodeConverter,
url_encoder: urlEncoder,
number_base_converter: numberBaseConverter
number_base_converter: numberBaseConverter,
yml_properties_converter: ymlPropertiesConverter
};
export default tools;
@@ -0,0 +1,67 @@
export const ymlPropertiesConverterEn = {
title: 'YML & Properties Converter',
description: 'Convert between YML/YAML and Properties configuration file formats',
select_format_type: 'Select Conversion Direction',
direction: {
yml_to_properties: 'YML to Properties',
properties_to_yml: 'Properties to YML'
},
actions: {
load_example: 'Load Example',
clear: 'Clear',
convert: 'Convert',
converting: 'Converting...',
copy: 'Copy',
copied: 'Copied',
download: 'Download'
},
advanced_options: {
show: 'Show Advanced Options',
hide: 'Hide Advanced Options',
properties: {
delimiter: 'Key-Value Delimiter',
delimiters: {
equals: 'Equals (=)',
colon: 'Colon (:)'
},
escape_unicode: 'Escape Unicode',
sort_keys: 'Sort Keys'
},
yml: {
indent: 'Indent Spaces',
quote_strings: 'Quote Strings',
sort_keys: 'Sort Keys'
},
description: 'These options will affect the format and structure of the conversion result.'
},
input: {
yml: 'YML/YAML Input',
properties: 'Properties Input',
yml_placeholder: 'Enter YML/YAML data...',
properties_placeholder: 'Enter Properties data...'
},
output: {
yml: 'YML/YAML Output',
properties: 'Properties Output',
yml_placeholder: 'Converted YML/YAML will appear here...',
properties_placeholder: 'Converted Properties will appear here...'
},
notes: {
title: 'Conversion Notes',
items: {
0: 'YML supports hierarchical structure, while Properties uses dots for hierarchy',
1: 'Unicode escapes in Properties files will be properly handled',
2: 'The conversion will try to preserve data structures, but some complex structures may be limited',
3: 'Arrays in Properties are represented as indexed keys (e.g.: list.0, list.1)'
}
},
errors: {
invalid_yml: 'Invalid YML/YAML format',
invalid_properties: 'Invalid Properties format',
conversion_error: 'Error occurred during conversion',
copy_failed: 'Copy failed:',
clipboard_error: 'Failed to copy to clipboard'
}
};
export default ymlPropertiesConverterEn;
@@ -0,0 +1,7 @@
import ymlPropertiesConverterZh from './zh';
import ymlPropertiesConverterEn from './en';
export default {
zh: ymlPropertiesConverterZh,
en: ymlPropertiesConverterEn
};
@@ -0,0 +1,67 @@
export const ymlPropertiesConverterZh = {
title: 'YML与Properties互转',
description: '在YML/YAML与Properties配置文件格式之间相互转换',
select_format_type: '选择转换方向',
direction: {
yml_to_properties: 'YML转Properties',
properties_to_yml: 'Properties转YML'
},
actions: {
load_example: '加载示例',
clear: '清空',
convert: '转换',
converting: '转换中...',
copy: '复制',
copied: '已复制',
download: '下载'
},
advanced_options: {
show: '显示高级选项',
hide: '隐藏高级选项',
properties: {
delimiter: '键值分隔符',
delimiters: {
equals: '等号 (=)',
colon: '冒号 (:)'
},
escape_unicode: 'Unicode转义',
sort_keys: '按键排序'
},
yml: {
indent: '缩进空格数',
quote_strings: '字符串加引号',
sort_keys: '按键排序'
},
description: '这些选项将影响转换结果的格式和结构。'
},
input: {
yml: 'YML/YAML 输入',
properties: 'Properties 输入',
yml_placeholder: '请输入YML/YAML数据...',
properties_placeholder: '请输入Properties数据...'
},
output: {
yml: 'YML/YAML 输出',
properties: 'Properties 输出',
yml_placeholder: '转换后的YML/YAML将显示在这里...',
properties_placeholder: '转换后的Properties将显示在这里...'
},
notes: {
title: '转换说明',
items: {
0: 'YML支持层级结构,而Properties使用点号表示层级',
1: 'Properties文件中的Unicode转义将被正确处理',
2: '转换过程会尽量保留数据结构,但某些复杂结构可能会受限',
3: '数组在Properties中表示为带索引的键(如: list.0, list.1'
}
},
errors: {
invalid_yml: '输入的YML/YAML格式无效',
invalid_properties: '输入的Properties格式无效',
conversion_error: '转换过程中发生错误',
copy_failed: '复制失败:',
clipboard_error: '复制到剪贴板失败'
}
};
export default ymlPropertiesConverterZh;
+2 -1
View File
@@ -26,7 +26,8 @@ export const zh = {
timezone_converter: tools.timezone_converter.zh,
unicode_converter: tools.unicode_converter.zh,
url_encoder: tools.url_encoder.zh,
number_base_converter: tools.number_base_converter.zh
number_base_converter: tools.number_base_converter.zh,
yml_properties_converter: tools.yml_properties_converter.zh
}
};
+7 -1
View File
@@ -2,7 +2,7 @@ import {
faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock,
faImage, faCogs, faFileCode, faKey, faFont,
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired,
faEraser, faCalculator
faEraser, faCalculator, faFileAlt
} from '@fortawesome/free-solid-svg-icons';
import { Tool } from '@/types/tools';
@@ -147,6 +147,12 @@ const tools: Tool[] = [
icon: faCalculator,
category: ['encoding'],
keywords: ['进制转换', '进制', '二进制', '八进制', '十进制', '十六进制', '二进制转换', '十六进制转换', 'binary', 'hex', 'decimal', 'octal', 'base conversion', 'jinzhi', 'jzzh', 'jz']
},
{
code: 'yml_properties_converter',
icon: faFileAlt,
category: ['code'],
keywords: ['yml', 'yaml', 'properties', 'yml转properties', 'properties转yml', '配置文件', '转换工具', 'yml互转properties', 'yaml互转properties', '配置转换', 'peizhi', 'pz', 'zhuanhuan', 'zh']
}
] as Tool[];