mirror of
https://github.com/justhtmls/html-tools.git
synced 2026-08-31 02:03:51 +08:00
feat: add 15 tools and filter check
This commit is contained in:
@@ -25,6 +25,14 @@ jobs:
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Validate filters
|
||||
run: node scripts/check-filter.js
|
||||
|
||||
- name: Update sitemap
|
||||
run: python3 scripts/update_sitemap.py
|
||||
@@ -46,4 +54,3 @@ jobs:
|
||||
git add sitemap.xml
|
||||
git commit -m "chore: auto-update sitemap.xml"
|
||||
git push
|
||||
|
||||
|
||||
+592
-36
@@ -7,7 +7,12 @@
|
||||
"name": "JSON 转 YAML",
|
||||
"slug": "json-to-yaml",
|
||||
"category": "converter",
|
||||
"tags": ["json", "yaml", "converter", "developer"],
|
||||
"tags": [
|
||||
"json",
|
||||
"yaml",
|
||||
"converter",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -27,7 +32,12 @@
|
||||
"name": "JSON 格式化工具",
|
||||
"slug": "json-formatter",
|
||||
"category": "converter",
|
||||
"tags": ["json", "formatter", "validator", "beautifier"],
|
||||
"tags": [
|
||||
"json",
|
||||
"formatter",
|
||||
"validator",
|
||||
"beautifier"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -47,7 +57,12 @@
|
||||
"name": "Base64 编码解码",
|
||||
"slug": "base64-encode",
|
||||
"category": "converter",
|
||||
"tags": ["base64", "encoder", "decoder", "converter"],
|
||||
"tags": [
|
||||
"base64",
|
||||
"encoder",
|
||||
"decoder",
|
||||
"converter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -67,7 +82,12 @@
|
||||
"name": "颜色选择器",
|
||||
"slug": "color-picker",
|
||||
"category": "developer",
|
||||
"tags": ["color", "picker", "design", "converter"],
|
||||
"tags": [
|
||||
"color",
|
||||
"picker",
|
||||
"design",
|
||||
"converter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -87,7 +107,11 @@
|
||||
"name": "正则表达式测试器",
|
||||
"slug": "regex-tester",
|
||||
"category": "developer",
|
||||
"tags": ["regex", "testing", "developer"],
|
||||
"tags": [
|
||||
"regex",
|
||||
"testing",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -107,7 +131,12 @@
|
||||
"name": "URL 编码解码",
|
||||
"slug": "url-encode",
|
||||
"category": "converter",
|
||||
"tags": ["url", "encoder", "decoder", "converter"],
|
||||
"tags": [
|
||||
"url",
|
||||
"encoder",
|
||||
"decoder",
|
||||
"converter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -127,7 +156,11 @@
|
||||
"name": "二维码生成器",
|
||||
"slug": "qr-generator",
|
||||
"category": "utility",
|
||||
"tags": ["qrcode", "generator", "utility"],
|
||||
"tags": [
|
||||
"qrcode",
|
||||
"generator",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -147,7 +180,12 @@
|
||||
"name": "安全密码生成器",
|
||||
"slug": "password-generator",
|
||||
"category": "utility",
|
||||
"tags": ["password", "security", "generator", "utility"],
|
||||
"tags": [
|
||||
"password",
|
||||
"security",
|
||||
"generator",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -167,7 +205,12 @@
|
||||
"name": "UUID 生成器",
|
||||
"slug": "uuid-generator",
|
||||
"category": "developer",
|
||||
"tags": ["uuid", "generator", "developer", "identifier"],
|
||||
"tags": [
|
||||
"uuid",
|
||||
"generator",
|
||||
"developer",
|
||||
"identifier"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -187,7 +230,12 @@
|
||||
"name": "字数统计工具",
|
||||
"slug": "word-counter",
|
||||
"category": "text",
|
||||
"tags": ["text", "counter", "word", "characters"],
|
||||
"tags": [
|
||||
"text",
|
||||
"counter",
|
||||
"word",
|
||||
"characters"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -207,7 +255,12 @@
|
||||
"name": "Unix 时间戳转换",
|
||||
"slug": "timestamp-converter",
|
||||
"category": "converter",
|
||||
"tags": ["timestamp", "unix", "datetime", "converter"],
|
||||
"tags": [
|
||||
"timestamp",
|
||||
"unix",
|
||||
"datetime",
|
||||
"converter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -227,7 +280,13 @@
|
||||
"name": "进制转换工具",
|
||||
"slug": "base-converter",
|
||||
"category": "converter",
|
||||
"tags": ["base", "converter", "binary", "hexadecimal", "octal"],
|
||||
"tags": [
|
||||
"base",
|
||||
"converter",
|
||||
"binary",
|
||||
"hexadecimal",
|
||||
"octal"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -247,7 +306,12 @@
|
||||
"name": "文本对比工具",
|
||||
"slug": "text-diff",
|
||||
"category": "text",
|
||||
"tags": ["text", "diff", "compare", "difference"],
|
||||
"tags": [
|
||||
"text",
|
||||
"diff",
|
||||
"compare",
|
||||
"difference"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -267,7 +331,13 @@
|
||||
"name": "JWT 解码器",
|
||||
"slug": "jwt-decoder",
|
||||
"category": "developer",
|
||||
"tags": ["jwt", "decoder", "json", "token", "authentication"],
|
||||
"tags": [
|
||||
"jwt",
|
||||
"decoder",
|
||||
"json",
|
||||
"token",
|
||||
"authentication"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -287,7 +357,12 @@
|
||||
"name": "图片转 Base64",
|
||||
"slug": "image-to-base64",
|
||||
"category": "image",
|
||||
"tags": ["image", "base64", "converter", "encoding"],
|
||||
"tags": [
|
||||
"image",
|
||||
"base64",
|
||||
"converter",
|
||||
"encoding"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -307,7 +382,12 @@
|
||||
"name": "XML 转 JSON",
|
||||
"slug": "xml-to-json",
|
||||
"category": "converter",
|
||||
"tags": ["xml", "json", "converter", "format"],
|
||||
"tags": [
|
||||
"xml",
|
||||
"json",
|
||||
"converter",
|
||||
"format"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -327,7 +407,12 @@
|
||||
"name": "Markdown 转 HTML",
|
||||
"slug": "markdown-to-html",
|
||||
"category": "text",
|
||||
"tags": ["markdown", "html", "converter", "editor"],
|
||||
"tags": [
|
||||
"markdown",
|
||||
"html",
|
||||
"converter",
|
||||
"editor"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -347,7 +432,13 @@
|
||||
"name": "哈希生成器",
|
||||
"slug": "hash-generator",
|
||||
"category": "developer",
|
||||
"tags": ["hash", "md5", "sha", "crypto", "security"],
|
||||
"tags": [
|
||||
"hash",
|
||||
"md5",
|
||||
"sha",
|
||||
"crypto",
|
||||
"security"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -367,7 +458,12 @@
|
||||
"name": "HTML 实体编码/解码",
|
||||
"slug": "html-entity",
|
||||
"category": "converter",
|
||||
"tags": ["html", "entity", "encode", "decode"],
|
||||
"tags": [
|
||||
"html",
|
||||
"entity",
|
||||
"encode",
|
||||
"decode"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -387,7 +483,12 @@
|
||||
"name": "大小写转换工具",
|
||||
"slug": "case-converter",
|
||||
"category": "text",
|
||||
"tags": ["text", "case", "converter", "format"],
|
||||
"tags": [
|
||||
"text",
|
||||
"case",
|
||||
"converter",
|
||||
"format"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -407,7 +508,12 @@
|
||||
"name": "CSS 压缩/格式化工具",
|
||||
"slug": "css-minifier",
|
||||
"category": "developer",
|
||||
"tags": ["css", "minifier", "beautifier", "formatter"],
|
||||
"tags": [
|
||||
"css",
|
||||
"minifier",
|
||||
"beautifier",
|
||||
"formatter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -427,7 +533,12 @@
|
||||
"name": "Cron 表达式生成器",
|
||||
"slug": "cron-generator",
|
||||
"category": "developer",
|
||||
"tags": ["cron", "scheduler", "expression", "generator"],
|
||||
"tags": [
|
||||
"cron",
|
||||
"scheduler",
|
||||
"expression",
|
||||
"generator"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -447,7 +558,12 @@
|
||||
"name": "百分比计算器",
|
||||
"slug": "percentage-calculator",
|
||||
"category": "utility",
|
||||
"tags": ["calculator", "percentage", "math", "utility"],
|
||||
"tags": [
|
||||
"calculator",
|
||||
"percentage",
|
||||
"math",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -467,7 +583,12 @@
|
||||
"name": "Lorem Ipsum 生成器",
|
||||
"slug": "lorem-ipsum",
|
||||
"category": "text",
|
||||
"tags": ["lorem", "ipsum", "placeholder", "generator"],
|
||||
"tags": [
|
||||
"lorem",
|
||||
"ipsum",
|
||||
"placeholder",
|
||||
"generator"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -487,7 +608,12 @@
|
||||
"name": "YAML 验证器",
|
||||
"slug": "yaml-validator",
|
||||
"category": "converter",
|
||||
"tags": ["yaml", "validator", "json", "converter"],
|
||||
"tags": [
|
||||
"yaml",
|
||||
"validator",
|
||||
"json",
|
||||
"converter"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -507,7 +633,12 @@
|
||||
"name": "URL Slug 生成器",
|
||||
"slug": "slug-generator",
|
||||
"category": "text",
|
||||
"tags": ["slug", "url", "generator", "seo"],
|
||||
"tags": [
|
||||
"slug",
|
||||
"url",
|
||||
"generator",
|
||||
"seo"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -527,7 +658,12 @@
|
||||
"name": "文本去重工具",
|
||||
"slug": "text-deduplicator",
|
||||
"category": "text",
|
||||
"tags": ["text", "dedupe", "cleanup", "list"],
|
||||
"tags": [
|
||||
"text",
|
||||
"dedupe",
|
||||
"cleanup",
|
||||
"list"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -547,7 +683,12 @@
|
||||
"name": "文本排序工具",
|
||||
"slug": "text-sorter",
|
||||
"category": "text",
|
||||
"tags": ["text", "sorter", "list", "utility"],
|
||||
"tags": [
|
||||
"text",
|
||||
"sorter",
|
||||
"list",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -567,7 +708,12 @@
|
||||
"name": "行号添加器",
|
||||
"slug": "line-numberer",
|
||||
"category": "text",
|
||||
"tags": ["text", "line", "number", "editor"],
|
||||
"tags": [
|
||||
"text",
|
||||
"line",
|
||||
"number",
|
||||
"editor"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -587,7 +733,12 @@
|
||||
"name": "文本清理器",
|
||||
"slug": "text-cleaner",
|
||||
"category": "text",
|
||||
"tags": ["text", "cleaner", "format", "utility"],
|
||||
"tags": [
|
||||
"text",
|
||||
"cleaner",
|
||||
"format",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -607,7 +758,12 @@
|
||||
"name": "CSV 转 JSON",
|
||||
"slug": "csv-to-json",
|
||||
"category": "converter",
|
||||
"tags": ["csv", "json", "converter", "table"],
|
||||
"tags": [
|
||||
"csv",
|
||||
"json",
|
||||
"converter",
|
||||
"table"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -627,7 +783,12 @@
|
||||
"name": "JSON 转 CSV",
|
||||
"slug": "json-to-csv",
|
||||
"category": "converter",
|
||||
"tags": ["json", "csv", "converter", "export"],
|
||||
"tags": [
|
||||
"json",
|
||||
"csv",
|
||||
"converter",
|
||||
"export"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -647,7 +808,12 @@
|
||||
"name": "URL 解析器",
|
||||
"slug": "url-parser",
|
||||
"category": "developer",
|
||||
"tags": ["url", "parser", "developer", "web"],
|
||||
"tags": [
|
||||
"url",
|
||||
"parser",
|
||||
"developer",
|
||||
"web"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -667,7 +833,12 @@
|
||||
"name": "颜色对比度检测",
|
||||
"slug": "contrast-checker",
|
||||
"category": "developer",
|
||||
"tags": ["color", "contrast", "accessibility", "design"],
|
||||
"tags": [
|
||||
"color",
|
||||
"contrast",
|
||||
"accessibility",
|
||||
"design"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -687,7 +858,12 @@
|
||||
"name": "密码强度检测",
|
||||
"slug": "password-strength",
|
||||
"category": "utility",
|
||||
"tags": ["password", "security", "checker", "utility"],
|
||||
"tags": [
|
||||
"password",
|
||||
"security",
|
||||
"checker",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -707,7 +883,12 @@
|
||||
"name": "日期差值计算器",
|
||||
"slug": "date-diff",
|
||||
"category": "utility",
|
||||
"tags": ["date", "time", "calculator", "utility"],
|
||||
"tags": [
|
||||
"date",
|
||||
"time",
|
||||
"calculator",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
@@ -721,6 +902,381 @@
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": true,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "js-formatter",
|
||||
"name": "JavaScript 格式化工具",
|
||||
"slug": "js-formatter",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"formatter",
|
||||
"beautifier",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "美化 JavaScript 代码并提升可读性",
|
||||
"longDescription": "JavaScript 格式化工具可以帮助你把凌乱的 JS 代码重新排版,支持常见缩进设置,方便阅读与分享。",
|
||||
"icon": "🧩",
|
||||
"color": "#f59e0b",
|
||||
"entry": "tools/js-formatter/app.html",
|
||||
"detail": "tools/js-formatter/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "html-formatter",
|
||||
"name": "HTML 格式化工具",
|
||||
"slug": "html-formatter",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"html",
|
||||
"formatter",
|
||||
"beautifier",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "整理 HTML 结构并自动缩进",
|
||||
"longDescription": "HTML 格式化工具支持对 HTML 片段进行自动缩进与换行,让结构更加清晰易读。",
|
||||
"icon": "🧱",
|
||||
"color": "#ef4444",
|
||||
"entry": "tools/html-formatter/app.html",
|
||||
"detail": "tools/html-formatter/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "sql-formatter",
|
||||
"name": "SQL 格式化工具",
|
||||
"slug": "sql-formatter",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"sql",
|
||||
"formatter",
|
||||
"database",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "格式化 SQL 语句,提升可读性",
|
||||
"longDescription": "SQL 格式化工具可以将复杂的 SQL 查询语句自动排版,突出关键字与层级结构。",
|
||||
"icon": "🗄️",
|
||||
"color": "#10b981",
|
||||
"entry": "tools/sql-formatter/app.html",
|
||||
"detail": "tools/sql-formatter/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "http-status",
|
||||
"name": "HTTP 状态码查询",
|
||||
"slug": "http-status",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"http",
|
||||
"status",
|
||||
"api",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "快速查询常见 HTTP 状态码含义",
|
||||
"longDescription": "HTTP 状态码查询工具整理了常用的状态码及说明,支持搜索过滤,适合开发调试与排查问题。",
|
||||
"icon": "🛰️",
|
||||
"color": "#0ea5e9",
|
||||
"entry": "tools/http-status/app.html",
|
||||
"detail": "tools/http-status/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "json-escape",
|
||||
"name": "JSON 字符串转义",
|
||||
"slug": "json-escape",
|
||||
"category": "converter",
|
||||
"tags": [
|
||||
"json",
|
||||
"escape",
|
||||
"converter",
|
||||
"string"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "在 JSON 字符串转义与反转义之间转换",
|
||||
"longDescription": "JSON 字符串转义工具可以把普通文本转换为 JSON 可用的转义格式,或将转义字符还原为可读文本。",
|
||||
"icon": "🧵",
|
||||
"color": "#6366f1",
|
||||
"entry": "tools/json-escape/app.html",
|
||||
"detail": "tools/json-escape/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "url-query-builder",
|
||||
"name": "URL 参数生成器",
|
||||
"slug": "url-query-builder",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"url",
|
||||
"query",
|
||||
"builder",
|
||||
"developer"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "批量生成 URL 查询参数并输出完整链接",
|
||||
"longDescription": "URL 参数生成器支持通过键值对批量生成查询参数,自动编码,快速得到完整链接。",
|
||||
"icon": "🧷",
|
||||
"color": "#14b8a6",
|
||||
"entry": "tools/url-query-builder/app.html",
|
||||
"detail": "tools/url-query-builder/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "text-replacer",
|
||||
"name": "文本查找替换",
|
||||
"slug": "text-replacer",
|
||||
"category": "text",
|
||||
"tags": [
|
||||
"text",
|
||||
"replace",
|
||||
"search",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "批量查找并替换文本内容",
|
||||
"longDescription": "文本查找替换工具支持快速替换关键词,可选择大小写与正则模式,适合清理文本或批量替换内容。",
|
||||
"icon": "🧲",
|
||||
"color": "#8b5cf6",
|
||||
"entry": "tools/text-replacer/app.html",
|
||||
"detail": "tools/text-replacer/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "line-ending-converter",
|
||||
"name": "行尾符转换器",
|
||||
"slug": "line-ending-converter",
|
||||
"category": "text",
|
||||
"tags": [
|
||||
"text",
|
||||
"line",
|
||||
"lf",
|
||||
"crlf"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "在 LF 与 CRLF 行尾符之间转换",
|
||||
"longDescription": "行尾符转换器可以快速将文本在 LF 和 CRLF 之间切换,适合跨系统协作与代码整理。",
|
||||
"icon": "↩️",
|
||||
"color": "#3b82f6",
|
||||
"entry": "tools/line-ending-converter/app.html",
|
||||
"detail": "tools/line-ending-converter/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "text-reverser",
|
||||
"name": "文本反转工具",
|
||||
"slug": "text-reverser",
|
||||
"category": "text",
|
||||
"tags": [
|
||||
"text",
|
||||
"reverse",
|
||||
"converter",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "支持整段或按行反转文本",
|
||||
"longDescription": "文本反转工具可以将文本按字符或按行反转,适合特殊排版、加密提示或趣味处理。",
|
||||
"icon": "🔁",
|
||||
"color": "#f97316",
|
||||
"entry": "tools/text-reverser/app.html",
|
||||
"detail": "tools/text-reverser/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "image-compressor",
|
||||
"name": "图片压缩工具",
|
||||
"slug": "image-compressor",
|
||||
"category": "image",
|
||||
"tags": [
|
||||
"image",
|
||||
"compress",
|
||||
"optimizer",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "本地压缩图片,减少文件体积",
|
||||
"longDescription": "图片压缩工具使用浏览器 Canvas 在本地压缩图片,支持调整质量与输出格式。",
|
||||
"icon": "🗜️",
|
||||
"color": "#22c55e",
|
||||
"entry": "tools/image-compressor/app.html",
|
||||
"detail": "tools/image-compressor/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "image-resizer",
|
||||
"name": "图片尺寸调整",
|
||||
"slug": "image-resizer",
|
||||
"category": "image",
|
||||
"tags": [
|
||||
"image",
|
||||
"resize",
|
||||
"editor",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "调整图片宽高,支持锁定比例",
|
||||
"longDescription": "图片尺寸调整工具可在浏览器中修改图片分辨率,支持保持原始比例并导出新图片。",
|
||||
"icon": "📐",
|
||||
"color": "#06b6d4",
|
||||
"entry": "tools/image-resizer/app.html",
|
||||
"detail": "tools/image-resizer/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "image-to-webp",
|
||||
"name": "图片转 WebP",
|
||||
"slug": "image-to-webp",
|
||||
"category": "image",
|
||||
"tags": [
|
||||
"image",
|
||||
"webp",
|
||||
"converter",
|
||||
"compression"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "将图片转换为 WebP 格式",
|
||||
"longDescription": "图片转 WebP 工具帮助你把 JPG/PNG 等格式转换为 WebP,减少体积并提升加载速度。",
|
||||
"icon": "🧪",
|
||||
"color": "#a855f7",
|
||||
"entry": "tools/image-to-webp/app.html",
|
||||
"detail": "tools/image-to-webp/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "unit-converter",
|
||||
"name": "单位换算器",
|
||||
"slug": "unit-converter",
|
||||
"category": "utility",
|
||||
"tags": [
|
||||
"unit",
|
||||
"converter",
|
||||
"length",
|
||||
"weight"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "长度、重量、温度等单位快速换算",
|
||||
"longDescription": "单位换算器支持常用长度、重量与温度单位的快速转换,适合日常与工作场景。",
|
||||
"icon": "📏",
|
||||
"color": "#ec4899",
|
||||
"entry": "tools/unit-converter/app.html",
|
||||
"detail": "tools/unit-converter/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "bmi-calculator",
|
||||
"name": "BMI 计算器",
|
||||
"slug": "bmi-calculator",
|
||||
"category": "utility",
|
||||
"tags": [
|
||||
"bmi",
|
||||
"health",
|
||||
"calculator",
|
||||
"utility"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "快速计算身体质量指数 BMI",
|
||||
"longDescription": "BMI 计算器可根据身高体重计算 BMI 并给出健康范围提示,适合日常健康管理。",
|
||||
"icon": "⚖️",
|
||||
"color": "#84cc16",
|
||||
"entry": "tools/bmi-calculator/app.html",
|
||||
"detail": "tools/bmi-calculator/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
},
|
||||
{
|
||||
"id": "gradient-generator",
|
||||
"name": "渐变色生成器",
|
||||
"slug": "gradient-generator",
|
||||
"category": "developer",
|
||||
"tags": [
|
||||
"gradient",
|
||||
"color",
|
||||
"css",
|
||||
"design"
|
||||
],
|
||||
"author": "JustHTMLs",
|
||||
"authorUrl": "https://github.com/justhtmls",
|
||||
"version": "1.0.0",
|
||||
"description": "生成 CSS 线性渐变并实时预览",
|
||||
"longDescription": "渐变色生成器提供色彩与方向控制,实时预览并输出 CSS 渐变代码。",
|
||||
"icon": "🌈",
|
||||
"color": "#f43f5e",
|
||||
"entry": "tools/gradient-generator/app.html",
|
||||
"detail": "tools/gradient-generator/index.html",
|
||||
"createdAt": "2025-12-23",
|
||||
"updatedAt": "2025-12-23",
|
||||
"featured": false,
|
||||
"repo": "https://github.com/justhtmls/html-tools"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const data = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'index.json'), 'utf8'));
|
||||
|
||||
function filterTools({ category = 'all', search = '' }) {
|
||||
const searchQuery = search.toLowerCase();
|
||||
return data.tools.filter((tool) => {
|
||||
const matchesCategory = category === 'all' || tool.category === category;
|
||||
const matchesSearch = !searchQuery ||
|
||||
tool.name.toLowerCase().includes(searchQuery) ||
|
||||
tool.description.toLowerCase().includes(searchQuery) ||
|
||||
tool.tags.some((tag) => tag.toLowerCase().includes(searchQuery));
|
||||
return matchesCategory && matchesSearch;
|
||||
});
|
||||
}
|
||||
|
||||
function countMatches(label, options, expectAtLeastIds = []) {
|
||||
const result = filterTools(options);
|
||||
const ids = new Set(result.map((tool) => tool.id));
|
||||
const missing = expectAtLeastIds.filter((id) => !ids.has(id));
|
||||
console.log(`\n[${label}] count=${result.length}`);
|
||||
if (missing.length) {
|
||||
console.log(` missing: ${missing.join(', ')}`);
|
||||
} else if (expectAtLeastIds.length) {
|
||||
console.log(' includes expected ids: OK');
|
||||
}
|
||||
return { result, missing };
|
||||
}
|
||||
|
||||
const checks = [];
|
||||
checks.push(countMatches('Search: JSON', { search: 'JSON' }, [
|
||||
'json-formatter',
|
||||
'json-to-yaml',
|
||||
'json-to-csv',
|
||||
'json-escape',
|
||||
]));
|
||||
|
||||
checks.push(countMatches('Search: 图片', { search: '图片' }, [
|
||||
'image-to-base64',
|
||||
'image-compressor',
|
||||
'image-resizer',
|
||||
'image-to-webp',
|
||||
]));
|
||||
|
||||
checks.push(countMatches('Search: format', { search: 'format' }, [
|
||||
'js-formatter',
|
||||
'html-formatter',
|
||||
'sql-formatter',
|
||||
]));
|
||||
|
||||
checks.push(countMatches('Category: image', { category: 'image' }));
|
||||
checks.push(countMatches('Category: developer', { category: 'developer' }, [
|
||||
'http-status',
|
||||
'url-query-builder',
|
||||
'gradient-generator',
|
||||
]));
|
||||
|
||||
const total = data.tools.length;
|
||||
console.log(`\n[Total tools] ${total}`);
|
||||
|
||||
const failures = checks.flatMap((check) => check.missing || []);
|
||||
if (failures.length) {
|
||||
console.log('\nResult: FAIL');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('\nResult: PASS');
|
||||
+180
@@ -450,4 +450,184 @@
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/js-formatter/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/js-formatter/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/html-formatter/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/html-formatter/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/sql-formatter/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/sql-formatter/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/http-status/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/http-status/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/json-escape/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/json-escape/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/url-query-builder/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/url-query-builder/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/text-replacer/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/text-replacer/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/line-ending-converter/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/line-ending-converter/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/text-reverser/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/text-reverser/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-compressor/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-compressor/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-resizer/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-resizer/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-to-webp/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/image-to-webp/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/unit-converter/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/unit-converter/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/bmi-calculator/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/bmi-calculator/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/gradient-generator/</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.htmls.dev/tools/gradient-generator/app.html</loc>
|
||||
<lastmod>2025-12-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BMI 计算器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/bmi-calculator/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #84cc16;
|
||||
--accent-soft: #84cc1633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #84cc16 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>BMI 计算器</h1>
|
||||
<p>快速计算身体质量指数 BMI</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>身高 (cm)</label>
|
||||
<input type="number" id="height" placeholder="例如 170">
|
||||
</div>
|
||||
<div>
|
||||
<label>体重 (kg)</label>
|
||||
<input type="number" id="weight" placeholder="例如 60">
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="calculate">计算 BMI</button>
|
||||
</div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<p class="muted">BMI 结果</p>
|
||||
<div class="result" id="bmi">--</div>
|
||||
<p class="muted" id="status">--</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const heightInput = document.getElementById('height');
|
||||
const weightInput = document.getElementById('weight');
|
||||
const calculateBtn = document.getElementById('calculate');
|
||||
const bmiEl = document.getElementById('bmi');
|
||||
const statusEl = document.getElementById('status');
|
||||
|
||||
function getStatus(bmi) {
|
||||
if (bmi < 18.5) return '偏瘦';
|
||||
if (bmi < 25) return '正常';
|
||||
if (bmi < 30) return '偏重';
|
||||
return '肥胖';
|
||||
}
|
||||
|
||||
function calculate() {
|
||||
const height = parseFloat(heightInput.value);
|
||||
const weight = parseFloat(weightInput.value);
|
||||
if (!height || !weight) {
|
||||
bmiEl.textContent = '--';
|
||||
statusEl.textContent = '--';
|
||||
return;
|
||||
}
|
||||
const bmi = weight / ((height / 100) ** 2);
|
||||
bmiEl.textContent = bmi.toFixed(2);
|
||||
statusEl.textContent = getStatus(bmi);
|
||||
}
|
||||
|
||||
calculateBtn.addEventListener('click', calculate);
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BMI 计算器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/bmi-calculator/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #84cc16;
|
||||
--accent-soft: #84cc1633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #84cc16 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>BMI 计算器</h1>
|
||||
<p>快速计算身体质量指数 BMI</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>BMI 计算器可根据身高体重计算 BMI 并给出健康范围提示,适合日常健康管理。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>输入简单</li>
|
||||
<li>即时计算</li>
|
||||
<li>健康区间提示</li>
|
||||
<li>本地离线</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>健康管理</li>
|
||||
<li>健身记录</li>
|
||||
<li>体重控制</li>
|
||||
<li>营养咨询</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/bmi-calculator" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>渐变色生成器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/gradient-generator/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f43f5e;
|
||||
--accent-soft: #f43f5e33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f43f5e 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>渐变色生成器</h1>
|
||||
<p>生成 CSS 线性渐变并实时预览</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>起始颜色</label>
|
||||
<input type="color" id="colorStart" value="#f43f5e">
|
||||
</div>
|
||||
<div>
|
||||
<label>结束颜色</label>
|
||||
<input type="color" id="colorEnd" value="#3b82f6">
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 12px;">
|
||||
<label>方向</label>
|
||||
<select id="direction">
|
||||
<option value="to right">从左到右</option>
|
||||
<option value="to bottom">从上到下</option>
|
||||
<option value="45deg">45°</option>
|
||||
<option value="135deg">135°</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="preview" id="preview" style="margin-top: 16px; min-height: 160px;"></div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<label>CSS 代码</label>
|
||||
<textarea id="cssOutput" class="code" readonly></textarea>
|
||||
<div class="actions">
|
||||
<button class="btn" id="copy">复制 CSS</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const colorStart = document.getElementById('colorStart');
|
||||
const colorEnd = document.getElementById('colorEnd');
|
||||
const direction = document.getElementById('direction');
|
||||
const preview = document.getElementById('preview');
|
||||
const cssOutput = document.getElementById('cssOutput');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function updateGradient() {
|
||||
const value = `linear-gradient(${direction.value}, ${colorStart.value}, ${colorEnd.value})`;
|
||||
preview.style.background = value;
|
||||
cssOutput.value = `background: ${value};`;
|
||||
}
|
||||
|
||||
[colorStart, colorEnd, direction].forEach(el => {
|
||||
el.addEventListener('input', updateGradient);
|
||||
});
|
||||
|
||||
copyBtn.addEventListener('click', () => {
|
||||
cssOutput.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
|
||||
updateGradient();
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>渐变色生成器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/gradient-generator/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f43f5e;
|
||||
--accent-soft: #f43f5e33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f43f5e 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>渐变色生成器</h1>
|
||||
<p>生成 CSS 线性渐变并实时预览</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>渐变色生成器提供色彩与方向控制,实时预览并输出 CSS 渐变代码。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>多方向选择</li>
|
||||
<li>实时预览</li>
|
||||
<li>输出 CSS 代码</li>
|
||||
<li>一键复制</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>UI 设计</li>
|
||||
<li>按钮背景</li>
|
||||
<li>海报配色</li>
|
||||
<li>前端样式</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/gradient-generator" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HTML 格式化工具</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/html-formatter/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #ef4444;
|
||||
--accent-soft: #ef444433;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #ef4444 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>HTML 格式化工具</h1>
|
||||
<p>整理 HTML 结构并自动缩进</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>输入 HTML</label>
|
||||
<textarea id="input" placeholder="粘贴 HTML 代码"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="格式化后的 HTML"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 16px;">
|
||||
<div style="min-width: 180px;">
|
||||
<label>缩进设置</label>
|
||||
<select id="indent">
|
||||
<option value="2" selected>2 空格</option>
|
||||
<option value="4">4 空格</option>
|
||||
<option value="tab">Tab</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="format">格式化</button>
|
||||
<button class="btn btn-secondary" id="clear">清空</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify-html.js"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const output = document.getElementById('output');
|
||||
const indentSelect = document.getElementById('indent');
|
||||
const formatBtn = document.getElementById('format');
|
||||
const clearBtn = document.getElementById('clear');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function formatHtml() {
|
||||
const value = input.value;
|
||||
if (!value.trim()) {
|
||||
output.value = '';
|
||||
return;
|
||||
}
|
||||
const indent = indentSelect.value;
|
||||
const useTabs = indent === 'tab';
|
||||
const options = {
|
||||
indent_size: useTabs ? 1 : Number(indent),
|
||||
indent_with_tabs: useTabs,
|
||||
};
|
||||
output.value = html_beautify(value, options);
|
||||
}
|
||||
|
||||
formatBtn.addEventListener('click', formatHtml);
|
||||
clearBtn.addEventListener('click', () => {
|
||||
input.value = '';
|
||||
output.value = '';
|
||||
});
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HTML 格式化工具 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/html-formatter/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #ef4444;
|
||||
--accent-soft: #ef444433;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #ef4444 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>HTML 格式化工具</h1>
|
||||
<p>整理 HTML 结构并自动缩进</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>HTML 格式化工具支持对 HTML 片段进行自动缩进与换行,让结构更加清晰易读。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>HTML 自动排版</li>
|
||||
<li>保持标签层级</li>
|
||||
<li>快速复制结果</li>
|
||||
<li>本地离线处理</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>整理页面模板</li>
|
||||
<li>优化 HTML 可读性</li>
|
||||
<li>调试组件结构</li>
|
||||
<li>教学示例排版</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/html-formatter" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HTTP 状态码查询</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/http-status/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #0ea5e9;
|
||||
--accent-soft: #0ea5e933;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #0ea5e9 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>HTTP 状态码查询</h1>
|
||||
<p>快速查询常见 HTTP 状态码含义</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="row" style="margin-bottom: 12px;">
|
||||
<div style="flex: 1;">
|
||||
<label>搜索状态码或关键词</label>
|
||||
<input type="text" id="search" placeholder="例如 404 / unauthorized / server">
|
||||
</div>
|
||||
</div>
|
||||
<div id="list" class="output-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const searchInput = document.getElementById('search');
|
||||
const list = document.getElementById('list');
|
||||
const statuses = [
|
||||
{ code: 200, title: 'OK', desc: '请求成功' },
|
||||
{ code: 201, title: 'Created', desc: '资源创建成功' },
|
||||
{ code: 202, title: 'Accepted', desc: '请求已接收,处理中' },
|
||||
{ code: 204, title: 'No Content', desc: '请求成功但无返回内容' },
|
||||
{ code: 301, title: 'Moved Permanently', desc: '永久重定向' },
|
||||
{ code: 302, title: 'Found', desc: '临时重定向' },
|
||||
{ code: 304, title: 'Not Modified', desc: '资源未修改,使用缓存' },
|
||||
{ code: 400, title: 'Bad Request', desc: '请求参数错误' },
|
||||
{ code: 401, title: 'Unauthorized', desc: '未授权或身份验证失败' },
|
||||
{ code: 403, title: 'Forbidden', desc: '服务器拒绝访问' },
|
||||
{ code: 404, title: 'Not Found', desc: '资源不存在' },
|
||||
{ code: 409, title: 'Conflict', desc: '请求冲突' },
|
||||
{ code: 413, title: 'Payload Too Large', desc: '请求体过大' },
|
||||
{ code: 415, title: 'Unsupported Media Type', desc: '不支持的媒体类型' },
|
||||
{ code: 429, title: 'Too Many Requests', desc: '请求过多被限流' },
|
||||
{ code: 500, title: 'Internal Server Error', desc: '服务器内部错误' },
|
||||
{ code: 502, title: 'Bad Gateway', desc: '网关错误' },
|
||||
{ code: 503, title: 'Service Unavailable', desc: '服务不可用' },
|
||||
{ code: 504, title: 'Gateway Timeout', desc: '网关超时' },
|
||||
];
|
||||
|
||||
function render(filter = '') {
|
||||
const keyword = filter.trim().toLowerCase();
|
||||
const filtered = statuses.filter(item => {
|
||||
return (
|
||||
item.code.toString().includes(keyword) ||
|
||||
item.title.toLowerCase().includes(keyword) ||
|
||||
item.desc.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
if (!filtered.length) {
|
||||
list.innerHTML = '<p class="muted">没有匹配的状态码</p>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = filtered.map(item => `
|
||||
<div style="padding: 10px 0; border-bottom: 1px solid #e2e8f0;">
|
||||
<div class="row" style="justify-content: space-between;">
|
||||
<strong>${item.code} ${item.title}</strong>
|
||||
<span class="chip">HTTP</span>
|
||||
</div>
|
||||
<p class="muted" style="margin-top: 6px;">${item.desc}</p>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
render();
|
||||
searchInput.addEventListener('input', (event) => render(event.target.value));
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HTTP 状态码查询 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/http-status/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #0ea5e9;
|
||||
--accent-soft: #0ea5e933;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #0ea5e9 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>HTTP 状态码查询</h1>
|
||||
<p>快速查询常见 HTTP 状态码含义</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>HTTP 状态码查询工具整理了常用的状态码及说明,支持搜索过滤,适合开发调试与排查问题。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>覆盖常见状态码</li>
|
||||
<li>关键词搜索</li>
|
||||
<li>分类说明</li>
|
||||
<li>本地快速查阅</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>接口调试</li>
|
||||
<li>错误排查</li>
|
||||
<li>学习 HTTP 协议</li>
|
||||
<li>写作或文档引用</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/http-status" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片压缩工具</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-compressor/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #22c55e;
|
||||
--accent-soft: #22c55e33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #22c55e 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片压缩工具</h1>
|
||||
<p>本地压缩图片,减少文件体积</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>选择图片</label>
|
||||
<input type="file" id="file" accept="image/*">
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<div style="flex: 1;">
|
||||
<label>压缩质量:<span id="qualityLabel">0.8</span></label>
|
||||
<input type="range" id="quality" min="0.1" max="1" step="0.05" value="0.8">
|
||||
</div>
|
||||
<div style="min-width: 160px;">
|
||||
<label>输出格式</label>
|
||||
<select id="format">
|
||||
<option value="image/jpeg">JPEG</option>
|
||||
<option value="image/webp">WebP</option>
|
||||
<option value="image/png">PNG</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="compress">开始压缩</button>
|
||||
<a class="btn btn-secondary" id="download" download>下载图片</a>
|
||||
</div>
|
||||
<p class="muted" id="sizeInfo">原图大小:-- / 压缩后:--</p>
|
||||
</div>
|
||||
<div>
|
||||
<label>预览</label>
|
||||
<div class="preview" id="preview">暂无预览</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const fileInput = document.getElementById('file');
|
||||
const qualityInput = document.getElementById('quality');
|
||||
const qualityLabel = document.getElementById('qualityLabel');
|
||||
const formatSelect = document.getElementById('format');
|
||||
const compressBtn = document.getElementById('compress');
|
||||
const preview = document.getElementById('preview');
|
||||
const sizeInfo = document.getElementById('sizeInfo');
|
||||
const downloadLink = document.getElementById('download');
|
||||
let image = new Image();
|
||||
let originalSize = 0;
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (!bytes) return '--';
|
||||
const units = ['B', 'KB', 'MB'];
|
||||
let value = bytes;
|
||||
let index = 0;
|
||||
while (value >= 1024 && index < units.length - 1) {
|
||||
value /= 1024;
|
||||
index++;
|
||||
}
|
||||
return `${value.toFixed(2)} ${units[index]}`;
|
||||
}
|
||||
|
||||
qualityInput.addEventListener('input', () => {
|
||||
qualityLabel.textContent = qualityInput.value;
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) return;
|
||||
originalSize = file.size;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
image = new Image();
|
||||
image.onload = () => {
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(image);
|
||||
sizeInfo.textContent = `原图大小:${formatBytes(originalSize)} / 压缩后:--`;
|
||||
};
|
||||
image.src = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
compressBtn.addEventListener('click', () => {
|
||||
if (!image.src) return;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const format = formatSelect.value;
|
||||
const quality = parseFloat(qualityInput.value);
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) return;
|
||||
const url = URL.createObjectURL(blob);
|
||||
const previewImg = new Image();
|
||||
previewImg.onload = () => URL.revokeObjectURL(url);
|
||||
previewImg.src = url;
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(previewImg);
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = `compressed.${format.split('/')[1]}`;
|
||||
sizeInfo.textContent = `原图大小:${formatBytes(originalSize)} / 压缩后:${formatBytes(blob.size)}`;
|
||||
}, format, format === 'image/png' ? undefined : quality);
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片压缩工具 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-compressor/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #22c55e;
|
||||
--accent-soft: #22c55e33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #22c55e 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片压缩工具</h1>
|
||||
<p>本地压缩图片,减少文件体积</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>图片压缩工具使用浏览器 Canvas 在本地压缩图片,支持调整质量与输出格式。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>质量可调</li>
|
||||
<li>多格式输出</li>
|
||||
<li>实时预览</li>
|
||||
<li>本地处理隐私安全</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>网站图片优化</li>
|
||||
<li>上传前压缩</li>
|
||||
<li>节省存储空间</li>
|
||||
<li>分享图片</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/image-compressor" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片尺寸调整</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-resizer/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #06b6d4;
|
||||
--accent-soft: #06b6d433;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #06b6d4 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片尺寸调整</h1>
|
||||
<p>调整图片宽高,支持锁定比例</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>选择图片</label>
|
||||
<input type="file" id="file" accept="image/*">
|
||||
<div class="grid" style="margin-top: 12px;">
|
||||
<div>
|
||||
<label>宽度 (px)</label>
|
||||
<input type="number" id="width" min="1">
|
||||
</div>
|
||||
<div>
|
||||
<label>高度 (px)</label>
|
||||
<input type="number" id="height" min="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 8px;">
|
||||
<label><input type="checkbox" id="lock" checked> 锁定比例</label>
|
||||
<div style="min-width: 160px;">
|
||||
<label>输出格式</label>
|
||||
<select id="format">
|
||||
<option value="image/png">PNG</option>
|
||||
<option value="image/jpeg">JPEG</option>
|
||||
<option value="image/webp">WebP</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="resize">生成新图片</button>
|
||||
<a class="btn btn-secondary" id="download" download>下载图片</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>预览</label>
|
||||
<div class="preview" id="preview">暂无预览</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const fileInput = document.getElementById('file');
|
||||
const widthInput = document.getElementById('width');
|
||||
const heightInput = document.getElementById('height');
|
||||
const lockInput = document.getElementById('lock');
|
||||
const formatSelect = document.getElementById('format');
|
||||
const resizeBtn = document.getElementById('resize');
|
||||
const preview = document.getElementById('preview');
|
||||
const downloadLink = document.getElementById('download');
|
||||
let image = new Image();
|
||||
let ratio = 1;
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
image = new Image();
|
||||
image.onload = () => {
|
||||
ratio = image.naturalWidth / image.naturalHeight;
|
||||
widthInput.value = image.naturalWidth;
|
||||
heightInput.value = image.naturalHeight;
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(image);
|
||||
};
|
||||
image.src = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
widthInput.addEventListener('input', () => {
|
||||
if (!lockInput.checked || !widthInput.value) return;
|
||||
heightInput.value = Math.round(Number(widthInput.value) / ratio);
|
||||
});
|
||||
|
||||
heightInput.addEventListener('input', () => {
|
||||
if (!lockInput.checked || !heightInput.value) return;
|
||||
widthInput.value = Math.round(Number(heightInput.value) * ratio);
|
||||
});
|
||||
|
||||
resizeBtn.addEventListener('click', () => {
|
||||
if (!image.src) return;
|
||||
const width = Number(widthInput.value);
|
||||
const height = Number(heightInput.value);
|
||||
if (!width || !height) return;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(image, 0, 0, width, height);
|
||||
const format = formatSelect.value;
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) return;
|
||||
const url = URL.createObjectURL(blob);
|
||||
const previewImg = new Image();
|
||||
previewImg.onload = () => URL.revokeObjectURL(url);
|
||||
previewImg.src = url;
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(previewImg);
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = `resized.${format.split('/')[1]}`;
|
||||
}, format, 0.92);
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片尺寸调整 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-resizer/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #06b6d4;
|
||||
--accent-soft: #06b6d433;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #06b6d4 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片尺寸调整</h1>
|
||||
<p>调整图片宽高,支持锁定比例</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>图片尺寸调整工具可在浏览器中修改图片分辨率,支持保持原始比例并导出新图片。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>自定义宽高</li>
|
||||
<li>锁定比例</li>
|
||||
<li>多格式导出</li>
|
||||
<li>实时预览</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>压缩分辨率</li>
|
||||
<li>适配社媒尺寸</li>
|
||||
<li>制作缩略图</li>
|
||||
<li>产品图片处理</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/image-resizer" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片转 WebP</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-to-webp/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #a855f7;
|
||||
--accent-soft: #a855f733;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #a855f7 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片转 WebP</h1>
|
||||
<p>将图片转换为 WebP 格式</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>选择图片</label>
|
||||
<input type="file" id="file" accept="image/*">
|
||||
<div style="margin-top: 12px;">
|
||||
<label>输出质量:<span id="qualityLabel">0.85</span></label>
|
||||
<input type="range" id="quality" min="0.1" max="1" step="0.05" value="0.85">
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="convert">转换为 WebP</button>
|
||||
<a class="btn btn-secondary" id="download" download>下载 WebP</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>预览</label>
|
||||
<div class="preview" id="preview">暂无预览</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const fileInput = document.getElementById('file');
|
||||
const qualityInput = document.getElementById('quality');
|
||||
const qualityLabel = document.getElementById('qualityLabel');
|
||||
const convertBtn = document.getElementById('convert');
|
||||
const preview = document.getElementById('preview');
|
||||
const downloadLink = document.getElementById('download');
|
||||
let image = new Image();
|
||||
|
||||
qualityInput.addEventListener('input', () => {
|
||||
qualityLabel.textContent = qualityInput.value;
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
image = new Image();
|
||||
image.onload = () => {
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(image);
|
||||
};
|
||||
image.src = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
convertBtn.addEventListener('click', () => {
|
||||
if (!image.src) return;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const quality = parseFloat(qualityInput.value);
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) return;
|
||||
const url = URL.createObjectURL(blob);
|
||||
const previewImg = new Image();
|
||||
previewImg.onload = () => URL.revokeObjectURL(url);
|
||||
previewImg.src = url;
|
||||
preview.innerHTML = '';
|
||||
preview.appendChild(previewImg);
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = 'converted.webp';
|
||||
}, 'image/webp', quality);
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>图片转 WebP - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/image-to-webp/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #a855f7;
|
||||
--accent-soft: #a855f733;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #a855f7 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>图片转 WebP</h1>
|
||||
<p>将图片转换为 WebP 格式</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>图片转 WebP 工具帮助你把 JPG/PNG 等格式转换为 WebP,减少体积并提升加载速度。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>WebP 转换</li>
|
||||
<li>质量可调</li>
|
||||
<li>本地处理</li>
|
||||
<li>快速下载</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>网站图片优化</li>
|
||||
<li>移动端节省流量</li>
|
||||
<li>批量转换</li>
|
||||
<li>CDN 优化</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/image-to-webp" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JavaScript 格式化工具</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/js-formatter/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f59e0b;
|
||||
--accent-soft: #f59e0b33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>JavaScript 格式化工具</h1>
|
||||
<p>美化 JavaScript 代码并提升可读性</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>输入 JavaScript</label>
|
||||
<textarea id="input" placeholder="粘贴需要格式化的 JS 代码"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="格式化后的代码"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 16px;">
|
||||
<div style="min-width: 180px;">
|
||||
<label>缩进设置</label>
|
||||
<select id="indent">
|
||||
<option value="2">2 空格</option>
|
||||
<option value="4" selected>4 空格</option>
|
||||
<option value="tab">Tab</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="format">格式化</button>
|
||||
<button class="btn btn-secondary" id="clear">清空</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="muted" style="margin-top: 10px;">提示:格式化不会执行代码,所有处理都在浏览器本地完成。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify.js"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const output = document.getElementById('output');
|
||||
const indentSelect = document.getElementById('indent');
|
||||
const formatBtn = document.getElementById('format');
|
||||
const clearBtn = document.getElementById('clear');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function formatCode() {
|
||||
const value = input.value;
|
||||
if (!value.trim()) {
|
||||
output.value = '';
|
||||
return;
|
||||
}
|
||||
const indent = indentSelect.value;
|
||||
const useTabs = indent === 'tab';
|
||||
const options = {
|
||||
indent_size: useTabs ? 1 : Number(indent),
|
||||
indent_with_tabs: useTabs,
|
||||
};
|
||||
output.value = js_beautify(value, options);
|
||||
}
|
||||
|
||||
formatBtn.addEventListener('click', formatCode);
|
||||
clearBtn.addEventListener('click', () => {
|
||||
input.value = '';
|
||||
output.value = '';
|
||||
});
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JavaScript 格式化工具 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/js-formatter/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f59e0b;
|
||||
--accent-soft: #f59e0b33;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>JavaScript 格式化工具</h1>
|
||||
<p>美化 JavaScript 代码并提升可读性</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>JavaScript 格式化工具可以帮助你把凌乱的 JS 代码重新排版,支持常见缩进设置,方便阅读与分享。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>多种缩进方案</li>
|
||||
<li>一键格式化</li>
|
||||
<li>快速复制结果</li>
|
||||
<li>纯前端本地处理</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>阅读压缩 JS 代码</li>
|
||||
<li>整理前端脚本</li>
|
||||
<li>分享代码片段</li>
|
||||
<li>团队协作前统一格式</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/js-formatter" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JSON 字符串转义</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/json-escape/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #6366f1;
|
||||
--accent-soft: #6366f133;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #6366f1 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>JSON 字符串转义</h1>
|
||||
<p>在 JSON 字符串转义与反转义之间转换</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>输入文本</label>
|
||||
<textarea id="input" placeholder="输入原始文本或转义后的字符串"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="转换后的结果"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="escape">转义</button>
|
||||
<button class="btn btn-secondary" id="unescape">反转义</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
<p class="muted" style="margin-top: 8px;">适用于生成 JSON 字符串、处理转义符等场景。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const output = document.getElementById('output');
|
||||
const escapeBtn = document.getElementById('escape');
|
||||
const unescapeBtn = document.getElementById('unescape');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function escapeText() {
|
||||
output.value = JSON.stringify(input.value).slice(1, -1);
|
||||
}
|
||||
|
||||
function unescapeText() {
|
||||
try {
|
||||
const value = JSON.parse('"' + input.value.replace(/"/g, '\"') + '"');
|
||||
output.value = value;
|
||||
} catch (error) {
|
||||
output.value = '无法解析:请检查转义字符格式';
|
||||
}
|
||||
}
|
||||
|
||||
escapeBtn.addEventListener('click', escapeText);
|
||||
unescapeBtn.addEventListener('click', unescapeText);
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JSON 字符串转义 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/json-escape/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #6366f1;
|
||||
--accent-soft: #6366f133;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #6366f1 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>JSON 字符串转义</h1>
|
||||
<p>在 JSON 字符串转义与反转义之间转换</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>JSON 字符串转义工具可以把普通文本转换为 JSON 可用的转义格式,或将转义字符还原为可读文本。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>一键转义/反转义</li>
|
||||
<li>支持换行与引号</li>
|
||||
<li>快速复制</li>
|
||||
<li>本地处理</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>调试接口返回文本</li>
|
||||
<li>处理 JSON 配置</li>
|
||||
<li>复制带引号的字符串</li>
|
||||
<li>生成测试数据</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/json-escape" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>行尾符转换器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/line-ending-converter/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #3b82f6;
|
||||
--accent-soft: #3b82f633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>行尾符转换器</h1>
|
||||
<p>在 LF 与 CRLF 行尾符之间转换</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>输入文本</label>
|
||||
<textarea id="input" placeholder="粘贴需要转换的文本"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="转换后的文本"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="toLf">转为 LF</button>
|
||||
<button class="btn btn-secondary" id="toCrlf">转为 CRLF</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
<p class="muted">当前行数:<span id="lines">0</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const output = document.getElementById('output');
|
||||
const toLfBtn = document.getElementById('toLf');
|
||||
const toCrlfBtn = document.getElementById('toCrlf');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
const linesEl = document.getElementById('lines');
|
||||
|
||||
function normalize(value) {
|
||||
return value.replace(/
|
||||
/g, '
|
||||
').replace(/
|
||||
/g, '
|
||||
');
|
||||
}
|
||||
|
||||
function updateLines(value) {
|
||||
const normalized = normalize(value);
|
||||
linesEl.textContent = normalized ? normalized.split('
|
||||
').length : '0';
|
||||
}
|
||||
|
||||
function convertToLf() {
|
||||
const normalized = normalize(input.value);
|
||||
output.value = normalized;
|
||||
updateLines(normalized);
|
||||
}
|
||||
|
||||
function convertToCrlf() {
|
||||
const normalized = normalize(input.value);
|
||||
output.value = normalized.replace(/
|
||||
/g, '
|
||||
');
|
||||
updateLines(normalized);
|
||||
}
|
||||
|
||||
input.addEventListener('input', () => updateLines(input.value));
|
||||
toLfBtn.addEventListener('click', convertToLf);
|
||||
toCrlfBtn.addEventListener('click', convertToCrlf);
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>行尾符转换器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/line-ending-converter/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #3b82f6;
|
||||
--accent-soft: #3b82f633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>行尾符转换器</h1>
|
||||
<p>在 LF 与 CRLF 行尾符之间转换</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>行尾符转换器可以快速将文本在 LF 和 CRLF 之间切换,适合跨系统协作与代码整理。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>一键转换行尾符</li>
|
||||
<li>统计行数</li>
|
||||
<li>支持大段文本</li>
|
||||
<li>结果可复制</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>Windows 与 macOS 协作</li>
|
||||
<li>Git 行尾符整理</li>
|
||||
<li>代码格式修复</li>
|
||||
<li>批量文本处理</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/line-ending-converter" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SQL 格式化工具</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/sql-formatter/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #10b981;
|
||||
--accent-soft: #10b98133;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #10b981 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>SQL 格式化工具</h1>
|
||||
<p>格式化 SQL 语句,提升可读性</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>输入 SQL</label>
|
||||
<textarea id="input" placeholder="粘贴 SQL 语句"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="格式化后的 SQL"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 16px;">
|
||||
<div style="min-width: 180px;">
|
||||
<label>缩进空格</label>
|
||||
<select id="indent">
|
||||
<option value="2" selected>2 空格</option>
|
||||
<option value="4">4 空格</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="format">格式化</button>
|
||||
<button class="btn btn-secondary" id="clear">清空</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sql-formatter@15.4.3/dist/sql-formatter.min.js"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const output = document.getElementById('output');
|
||||
const indentSelect = document.getElementById('indent');
|
||||
const formatBtn = document.getElementById('format');
|
||||
const clearBtn = document.getElementById('clear');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function formatSql() {
|
||||
const value = input.value;
|
||||
if (!value.trim()) {
|
||||
output.value = '';
|
||||
return;
|
||||
}
|
||||
const indent = Number(indentSelect.value);
|
||||
output.value = sqlFormatter.format(value, { indent });
|
||||
}
|
||||
|
||||
formatBtn.addEventListener('click', formatSql);
|
||||
clearBtn.addEventListener('click', () => {
|
||||
input.value = '';
|
||||
output.value = '';
|
||||
});
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SQL 格式化工具 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/sql-formatter/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #10b981;
|
||||
--accent-soft: #10b98133;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #10b981 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>SQL 格式化工具</h1>
|
||||
<p>格式化 SQL 语句,提升可读性</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>SQL 格式化工具可以将复杂的 SQL 查询语句自动排版,突出关键字与层级结构。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>SQL 自动排版</li>
|
||||
<li>支持常见数据库语法</li>
|
||||
<li>快速复制结果</li>
|
||||
<li>纯前端处理</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>阅读复杂 SQL</li>
|
||||
<li>整理数据库脚本</li>
|
||||
<li>代码审查</li>
|
||||
<li>教学示例</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/sql-formatter" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文本查找替换</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/text-replacer/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #8b5cf6;
|
||||
--accent-soft: #8b5cf633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #8b5cf6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>文本查找替换</h1>
|
||||
<p>批量查找并替换文本内容</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div>
|
||||
<label>原始文本</label>
|
||||
<textarea id="input" placeholder="粘贴需要处理的文本"></textarea>
|
||||
</div>
|
||||
<div class="grid" style="margin-top: 16px;">
|
||||
<div>
|
||||
<label>查找内容</label>
|
||||
<input type="text" id="findText" placeholder="输入要查找的文本">
|
||||
</div>
|
||||
<div>
|
||||
<label>替换为</label>
|
||||
<input type="text" id="replaceText" placeholder="替换内容">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<label><input type="checkbox" id="ignoreCase"> 忽略大小写</label>
|
||||
<label><input type="checkbox" id="useRegex"> 使用正则</label>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="replace">执行替换</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="替换后的文本"></textarea>
|
||||
<p class="muted">替换次数:<span id="count">0</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const findText = document.getElementById('findText');
|
||||
const replaceText = document.getElementById('replaceText');
|
||||
const ignoreCase = document.getElementById('ignoreCase');
|
||||
const useRegex = document.getElementById('useRegex');
|
||||
const replaceBtn = document.getElementById('replace');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
const output = document.getElementById('output');
|
||||
const countEl = document.getElementById('count');
|
||||
|
||||
function escapeRegExp(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function replaceAll() {
|
||||
const source = input.value;
|
||||
const findValue = findText.value;
|
||||
if (!findValue) {
|
||||
output.value = source;
|
||||
countEl.textContent = '0';
|
||||
return;
|
||||
}
|
||||
const flags = ignoreCase.checked ? 'gi' : 'g';
|
||||
const pattern = useRegex.checked ? findValue : escapeRegExp(findValue);
|
||||
const regex = new RegExp(pattern, flags);
|
||||
const matches = source.match(regex);
|
||||
const result = source.replace(regex, replaceText.value);
|
||||
output.value = result;
|
||||
countEl.textContent = matches ? matches.length : '0';
|
||||
}
|
||||
|
||||
replaceBtn.addEventListener('click', replaceAll);
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文本查找替换 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/text-replacer/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #8b5cf6;
|
||||
--accent-soft: #8b5cf633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #8b5cf6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>文本查找替换</h1>
|
||||
<p>批量查找并替换文本内容</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>文本查找替换工具支持快速替换关键词,可选择大小写与正则模式,适合清理文本或批量替换内容。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>支持正则替换</li>
|
||||
<li>大小写控制</li>
|
||||
<li>统计替换次数</li>
|
||||
<li>快速复制</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>清理文档内容</li>
|
||||
<li>批量替换变量</li>
|
||||
<li>日志处理</li>
|
||||
<li>文本纠错</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/text-replacer" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文本反转工具</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/text-reverser/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f97316;
|
||||
--accent-soft: #f9731633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f97316 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>文本反转工具</h1>
|
||||
<p>支持整段或按行反转文本</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div>
|
||||
<label>输入文本</label>
|
||||
<textarea id="input" placeholder="粘贴需要反转的文本"></textarea>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 12px;">
|
||||
<div style="min-width: 200px;">
|
||||
<label>反转模式</label>
|
||||
<select id="mode">
|
||||
<option value="chars">整段字符反转</option>
|
||||
<option value="lines">按行顺序反转</option>
|
||||
<option value="each-line">每行内部反转</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="convert">开始反转</button>
|
||||
<button class="btn btn-secondary" id="copy">复制结果</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<label>输出结果</label>
|
||||
<textarea id="output" readonly placeholder="反转后的文本"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
const mode = document.getElementById('mode');
|
||||
const output = document.getElementById('output');
|
||||
const convertBtn = document.getElementById('convert');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
|
||||
function reverseText() {
|
||||
const value = input.value;
|
||||
if (!value) {
|
||||
output.value = '';
|
||||
return;
|
||||
}
|
||||
if (mode.value === 'chars') {
|
||||
output.value = value.split('').reverse().join('');
|
||||
} else if (mode.value === 'lines') {
|
||||
output.value = value.split(/
|
||||
?
|
||||
/).reverse().join('
|
||||
');
|
||||
} else {
|
||||
output.value = value.split(/
|
||||
?
|
||||
/).map(line => line.split('').reverse().join('')).join('
|
||||
');
|
||||
}
|
||||
}
|
||||
|
||||
convertBtn.addEventListener('click', reverseText);
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!output.value) return;
|
||||
output.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文本反转工具 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/text-reverser/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #f97316;
|
||||
--accent-soft: #f9731633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #f97316 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>文本反转工具</h1>
|
||||
<p>支持整段或按行反转文本</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>文本反转工具可以将文本按字符或按行反转,适合特殊排版、加密提示或趣味处理。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>多种反转模式</li>
|
||||
<li>即时处理</li>
|
||||
<li>复制结果</li>
|
||||
<li>支持多行文本</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>趣味文本</li>
|
||||
<li>镜像排版</li>
|
||||
<li>加密提示</li>
|
||||
<li>文本处理实验</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/text-reverser" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>单位换算器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/unit-converter/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #ec4899;
|
||||
--accent-soft: #ec489933;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #ec4899 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>单位换算器</h1>
|
||||
<p>长度、重量、温度等单位快速换算</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>单位类型</label>
|
||||
<select id="category">
|
||||
<option value="length">长度</option>
|
||||
<option value="weight">重量</option>
|
||||
<option value="temperature">温度</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label>输入数值</label>
|
||||
<input type="number" id="value" placeholder="输入数值">
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid" style="margin-top: 12px;">
|
||||
<div>
|
||||
<label>从</label>
|
||||
<select id="fromUnit"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label>到</label>
|
||||
<select id="toUnit"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<p class="muted">换算结果</p>
|
||||
<div class="result" id="result">--</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const categorySelect = document.getElementById('category');
|
||||
const valueInput = document.getElementById('value');
|
||||
const fromUnitSelect = document.getElementById('fromUnit');
|
||||
const toUnitSelect = document.getElementById('toUnit');
|
||||
const resultEl = document.getElementById('result');
|
||||
|
||||
const units = {
|
||||
length: {
|
||||
name: '长度',
|
||||
base: 'm',
|
||||
items: {
|
||||
m: 1,
|
||||
km: 1000,
|
||||
cm: 0.01,
|
||||
mm: 0.001,
|
||||
inch: 0.0254,
|
||||
ft: 0.3048,
|
||||
},
|
||||
},
|
||||
weight: {
|
||||
name: '重量',
|
||||
base: 'kg',
|
||||
items: {
|
||||
kg: 1,
|
||||
g: 0.001,
|
||||
lb: 0.45359237,
|
||||
oz: 0.0283495231,
|
||||
},
|
||||
},
|
||||
temperature: {
|
||||
name: '温度',
|
||||
items: {
|
||||
c: '摄氏度 (°C)',
|
||||
f: '华氏度 (°F)',
|
||||
k: '开尔文 (K)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function populateUnits() {
|
||||
const category = categorySelect.value;
|
||||
const unitSet = units[category];
|
||||
fromUnitSelect.innerHTML = '';
|
||||
toUnitSelect.innerHTML = '';
|
||||
if (category === 'temperature') {
|
||||
Object.entries(unitSet.items).forEach(([key, label]) => {
|
||||
const option1 = new Option(label, key);
|
||||
const option2 = new Option(label, key);
|
||||
fromUnitSelect.add(option1);
|
||||
toUnitSelect.add(option2);
|
||||
});
|
||||
} else {
|
||||
Object.keys(unitSet.items).forEach((key) => {
|
||||
const option1 = new Option(key, key);
|
||||
const option2 = new Option(key, key);
|
||||
fromUnitSelect.add(option1);
|
||||
toUnitSelect.add(option2);
|
||||
});
|
||||
}
|
||||
toUnitSelect.selectedIndex = 1;
|
||||
calculate();
|
||||
}
|
||||
|
||||
function convertTemperature(value, from, to) {
|
||||
let celsius = value;
|
||||
if (from === 'f') celsius = (value - 32) * 5 / 9;
|
||||
if (from === 'k') celsius = value - 273.15;
|
||||
let result = celsius;
|
||||
if (to === 'f') result = celsius * 9 / 5 + 32;
|
||||
if (to === 'k') result = celsius + 273.15;
|
||||
return result;
|
||||
}
|
||||
|
||||
function calculate() {
|
||||
const value = parseFloat(valueInput.value);
|
||||
if (Number.isNaN(value)) {
|
||||
resultEl.textContent = '--';
|
||||
return;
|
||||
}
|
||||
const category = categorySelect.value;
|
||||
if (category === 'temperature') {
|
||||
const result = convertTemperature(value, fromUnitSelect.value, toUnitSelect.value);
|
||||
resultEl.textContent = `${result.toFixed(2)}`;
|
||||
return;
|
||||
}
|
||||
const factorFrom = units[category].items[fromUnitSelect.value];
|
||||
const factorTo = units[category].items[toUnitSelect.value];
|
||||
const baseValue = value * factorFrom;
|
||||
const result = baseValue / factorTo;
|
||||
resultEl.textContent = result.toFixed(4);
|
||||
}
|
||||
|
||||
categorySelect.addEventListener('change', populateUnits);
|
||||
valueInput.addEventListener('input', calculate);
|
||||
fromUnitSelect.addEventListener('change', calculate);
|
||||
toUnitSelect.addEventListener('change', calculate);
|
||||
|
||||
populateUnits();
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>单位换算器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/unit-converter/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #ec4899;
|
||||
--accent-soft: #ec489933;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #ec4899 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>单位换算器</h1>
|
||||
<p>长度、重量、温度等单位快速换算</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>单位换算器支持常用长度、重量与温度单位的快速转换,适合日常与工作场景。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>多类别单位</li>
|
||||
<li>实时换算</li>
|
||||
<li>简单易用</li>
|
||||
<li>无需网络</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>工程计算</li>
|
||||
<li>出行换算</li>
|
||||
<li>教学演示</li>
|
||||
<li>日常查询</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/unit-converter" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>URL 参数生成器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/url-query-builder/app.html">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #14b8a6;
|
||||
--accent-soft: #14b8a633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #14b8a6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 26px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="url"],
|
||||
input[type="file"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.output-box {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed var(--border);
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.result {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>URL 参数生成器</h1>
|
||||
<p>批量生成 URL 查询参数并输出完整链接</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>基础 URL</label>
|
||||
<input type="url" id="baseUrl" placeholder="https://example.com/page">
|
||||
</div>
|
||||
<div>
|
||||
<label>参数列表(每行 key=value)</label>
|
||||
<textarea id="params" placeholder="utm_source=wechat
|
||||
utm_medium=social
|
||||
user=chao"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" id="build">生成链接</button>
|
||||
<button class="btn btn-secondary" id="copy">复制链接</button>
|
||||
</div>
|
||||
<div class="output-box" style="margin-top: 16px;">
|
||||
<label>完整 URL</label>
|
||||
<input type="text" id="fullUrl" readonly class="code" placeholder="生成后的完整链接">
|
||||
<label style="margin-top: 10px; display: block;">查询字符串</label>
|
||||
<textarea id="queryString" readonly class="code" placeholder="?key=value&..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const baseUrlInput = document.getElementById('baseUrl');
|
||||
const paramsInput = document.getElementById('params');
|
||||
const buildBtn = document.getElementById('build');
|
||||
const copyBtn = document.getElementById('copy');
|
||||
const fullUrlOutput = document.getElementById('fullUrl');
|
||||
const queryOutput = document.getElementById('queryString');
|
||||
|
||||
function buildUrl() {
|
||||
let base = baseUrlInput.value.trim();
|
||||
let hash = '';
|
||||
let queryPart = '';
|
||||
if (base.includes('#')) {
|
||||
const parts = base.split('#');
|
||||
base = parts[0];
|
||||
hash = parts.slice(1).join('#');
|
||||
}
|
||||
if (base.includes('?')) {
|
||||
const parts = base.split('?');
|
||||
base = parts[0];
|
||||
queryPart = parts.slice(1).join('?');
|
||||
}
|
||||
const params = new URLSearchParams(queryPart);
|
||||
paramsInput.value.split('
|
||||
').forEach(line => {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) return;
|
||||
const index = trimmed.indexOf('=');
|
||||
if (index === -1) {
|
||||
params.append(trimmed, '');
|
||||
return;
|
||||
}
|
||||
const key = trimmed.slice(0, index).trim();
|
||||
const value = trimmed.slice(index + 1).trim();
|
||||
params.set(key, value);
|
||||
});
|
||||
const queryString = params.toString();
|
||||
const url = base ? `${base}${queryString ? '?' + queryString : ''}${hash ? '#' + hash : ''}` : queryString;
|
||||
fullUrlOutput.value = url;
|
||||
queryOutput.value = queryString ? '?' + queryString : '';
|
||||
}
|
||||
|
||||
buildBtn.addEventListener('click', buildUrl);
|
||||
copyBtn.addEventListener('click', () => {
|
||||
if (!fullUrlOutput.value) return;
|
||||
fullUrlOutput.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<link rel="icon" href="../../favicon.svg">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>URL 参数生成器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/url-query-builder/">
|
||||
<style>
|
||||
:root {
|
||||
--accent: #14b8a6;
|
||||
--accent-soft: #14b8a633;
|
||||
--bg: #0f172a;
|
||||
--text: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #14b8a6 0%, #0f172a 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.3rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.features li {
|
||||
padding: 8px 0;
|
||||
color: #334155;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.features li:before {
|
||||
content: "✓";
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 26px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin: 6px 10px 6px 0;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.preview {
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview iframe {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>URL 参数生成器</h1>
|
||||
<p>批量生成 URL 查询参数并输出完整链接</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>关于这个工具</h2>
|
||||
<p>URL 参数生成器支持通过键值对批量生成查询参数,自动编码,快速得到完整链接。</p>
|
||||
|
||||
<h2>功能特点</h2>
|
||||
<ul class="features">
|
||||
<li>按行输入参数</li>
|
||||
<li>自动编码</li>
|
||||
<li>支持追加已有参数</li>
|
||||
<li>一键复制</li>
|
||||
</ul>
|
||||
|
||||
<h2>使用场景</h2>
|
||||
<ul class="features">
|
||||
<li>生成 UTM 链接</li>
|
||||
<li>调试 API 请求</li>
|
||||
<li>批量构造 URL</li>
|
||||
<li>分享带参数链接</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 24px;">
|
||||
<a href="app.html" class="btn">开始使用</a>
|
||||
<a href="https://github.com/justhtmls/html-tools/tree/main/tools/url-query-builder" target="_blank" class="btn btn-secondary">查看源码</a>
|
||||
<a href="../../index.html" class="btn btn-secondary">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>快速预览</h2>
|
||||
<div class="preview">
|
||||
<iframe src="app.html" loading="lazy"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user