diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..298ff3d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,55 @@ +name: Build + +on: + push: + branches: [main] + paths: + - "inbox/**" + - "scripts/**" + - ".github/workflows/build.yml" + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: build + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: 检出仓库 + uses: actions/checkout@v4 + + - name: 安装 Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: 安装依赖 + run: | + pip install Pillow + if ! command -v rsvg-convert >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq librsvg2-bin + fi + + - name: 构建 + id: build + env: + TINYPNG_KEY: ${{ secrets.TINYPNG_KEY }} + run: python scripts/build.py --repo . + + - name: 提交并推送 + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + if git diff --cached --quiet; then + echo "没有需要提交的变更" + else + git commit -m "ci: 自动构建(新增 ${{ steps.build.outputs.added }} 个图标)" + git push + fi diff --git a/README.md b/README.md index 7fe080e..69f6ad0 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,120 @@
- logo -

HD-Icons:高清仪表盘图标

-

1024×1024 超清分辨率 · 无损压缩优化 · 多种样式适配

+ HD-Icons + +# HD-Icons + +**为仪表盘而生的高清图标库** + +1024×1024 超清导出 · TinyPNG 无损压缩 · 圆角矩形 / 圆形 / SVG 三种风格 + +[![GitHub stars](https://img.shields.io/github/stars/xushier/HD-Icons?style=flat-square&logo=github&color=ff6b6b)](https://github.com/xushier/HD-Icons/stargazers) +[![License](https://img.shields.io/github/license/xushier/HD-Icons?style=flat-square&color=96ceb4)](https://github.com/xushier/HD-Icons/blob/master/LICENSE) +[![Last commit](https://img.shields.io/github/last-commit/xushier/HD-Icons?style=flat-square&color=6c5ce7)](https://github.com/xushier/HD-Icons/commits/main) +[![jsDelivr hits](https://data.jsdelivr.com/v1/package/gh/xushier/HD-Icons/badge?style=rounded)](https://www.jsdelivr.com/package/gh/xushier/HD-Icons) + +**共 1754 个图标,持续更新中**
+--- +## ✨ 特性 + +- **超清分辨率** — 所有 PNG 均为 1024×1024,任意缩放依旧锐利 +- **无损压缩** — 每张图标经 TinyPNG 压缩,体积更小、画质不变 +- **三种风格** — 圆角矩形、圆形(PNG)与矢量(SVG),命名一一对应 +- **自动构建** — 新图标入库后,索引、预览图、数量统计全部自动更新 + +## 📊 图标统计 + +| 风格 | 目录 | 数量 | +|------|------|------| +| 📦 圆角矩形 | `border-radius/` | 1083 | +| ⭕ 圆形 | `circle/` | 124 | +| 🎨 SVG 矢量 | `svg/` | 547 | + +## 🚀 使用 + +### 方式一:Docker 图标站(推荐) + +部署 [HD-Icons-docker](https://github.com/xushier/HD-Icons-docker),自动同步本仓库更新,支持一键复制、移动端适配与自定义上传。 + +| 日间模式 | 夜间模式 | +|----------|----------| +| 日间模式 | 夜间模式 | + +
+📱 移动端适配 / 一键复制 / 自定义上传 + +| 移动端自适应 | 一键复制地址 | 自定义上传 | +|----------|----------|----------| +| 移动端 | 一键复制 | 自定义上传 | + +
+ +### 方式二:直链引用 + +GitHub Raw(可直连 GitHub 时使用): + +``` +https://raw.githubusercontent.com/xushier/HD-Icons/main/border-radius/图标名.png +``` + +jsDelivr CDN(无法直连 GitHub 或需要加速时使用): + +``` +https://cdn.jsdelivr.net/gh/xushier/HD-Icons/border-radius/图标名.png +``` + +把 `图标名` 替换为实际文件名(可在 [icons.json](icons.json) 或下方预览图中查找),目录按需替换为 `border-radius`、`circle` 或 `svg`。 + +### 方式三:App 图标包 + +Yamby、Hills 等安卓应用可直接订阅图标索引: + +``` +https://raw.githubusercontent.com/xushier/HD-Icons/main/icons.json +``` + +> 如无响应,请开启代理环境,或使用 [HD-Icons-docker](https://github.com/xushier/HD-Icons-docker) 自行部署。 + +## 🖼️ 图标预览 + +### 📦 圆角矩形(1083)
- - [![GitHub stars](https://img.shields.io/github/stars/xushier/HD-Icons?style=for-the-badge&logo=github&color=ff6b6b)](https://github.com/xushier/HD-Icons/stargazers) - [![GitHub forks](https://img.shields.io/github/forks/xushier/HD-Icons?style=for-the-badge&logo=github&color=4ecdc4)](https://github.com/xushier/HD-Icons/network) - [![GitHub issues](https://img.shields.io/github/issues/xushier/HD-Icons?style=for-the-badge&logo=github&color=45b7d1)](https://github.com/xushier/HD-Icons/issues) - [![GitHub license](https://img.shields.io/github/license/xushier/HD-Icons?style=for-the-badge&logo=github&color=96ceb4)](https://github.com/xushier/HD-Icons/blob/master/LICENSE) - - - [![GitHub release](https://img.shields.io/github/release/xushier/HD-Icons?style=for-the-badge&logo=github&color=ffd93d)](https://github.com/xushier/HD-Icons/releases) - [![GitHub last commit](https://img.shields.io/github/last-commit/xushier/HD-Icons?style=for-the-badge&logo=github&color=6c5ce7)](https://github.com/xushier/HD-Icons/commits/main) - [![GitHub repo size](https://img.shields.io/github/repo-size/xushier/HD-Icons?style=for-the-badge&logo=github&color=a29bfe)](https://github.com/xushier/HD-Icons) - - - [![jsDelivr hits](https://data.jsdelivr.com/v1/package/gh/xushier/HD-Icons/badge?style=rounded)](https://www.jsdelivr.com/package/gh/xushier/HD-Icons) - + 圆角矩形图标预览
+### ⭕ 圆形(124) +
- - -
- 📖 项目简介 • - 🚀 使用说明 • - ✨ 图标预览 • - 🎯 请求图标 -
- - -
- GitHub activity -
- + 圆形图标预览
+### 🎨 SVG 矢量(547) - +
+点击展开 SVG 图标预览 +
+ SVG 图标预览 +
+
-## 📝 项目简介 +## 🎯 请求与贡献图标 -> 🎯 **使命**:为 Unraid Docker 容器和各类仪表盘应用提供高质量、标准化的图标解决方案 - -### ✨ 核心特性 - -| 特性 | 描述 | -|------|-----| -| 🖼️ **超清分辨率** | 1024×1024 像素,确保在任何尺寸下都清晰锐利 | -| 🗜️ **无损压缩** | 所有图标经过无损压缩,体积更小,质量不变 | -| 🎨 **优化显示** | 图标主体适当放大,满足各种使用场景 | -| 📁 **多样样式** | 提供 `border-radius`(圆角矩形)、 `circle`(圆形)和 `svg`(矢量)三种风格 | -| 🔄 **持续更新** | 不定期添加新图标,满足不断增长的需求 | - -### 🎯 适用场景 - -本项目最初为 `Unraid Docker` 容器图标展示而设计,现已扩展支持多种仪表盘应用、部分APP及其他用途: +- 缺少你需要的图标?[提交 Issue](https://github.com/xushier/HD-Icons/issues/new/choose) 即可 +- 想贡献图标?Fork 本仓库,把做好的图标(1024×1024 PNG 或 SVG)放进 `inbox/` 对应子目录,提交 PR,压缩入库、索引更新、预览图生成全部自动完成 +- 命名规范:小写英文单词 + 连字符 + 序号,如 `google-map-1.png` +
+📖 适用场景 +本项目最初为 Unraid Docker 容器图标展示而设计,现已扩展支持多种仪表盘应用、部分 App 及其他用途: | 应用程序 | 描述 | 链接 | 备注 | |----------|------|------|------| | **FlatNas** | 新晋现代化仪表盘 | [🔗](https://github.com/Garry-QD/FlatNas) | 开源免费 | -| **Sun-Panel** | 适合国人体质的现代化仪表盘 | [🔗](https://github.com/hslr-s/sun-panel) | 1.3.0及之前版本开源,新版Pro授权99永久 | +| **Sun-Panel** | 适合国人体质的现代化仪表盘 | [🔗](https://github.com/hslr-s/sun-panel) | 1.3.0 及之前版本开源,新版 Pro 授权 99 永久 | | **Dashy** | 现代化仪表盘 | [🔗](https://github.com/Lissy93/dashy) | 开源免费 | | **Homer Dashboard** | 简洁的静态主页 | [🔗](https://github.com/bastienwirtz/homer) | 开源免费 | | **Heimdall** | 应用程序仪表盘 | [🔗](https://github.com/linuxserver/Heimdall) | 开源免费 | @@ -74,11 +122,10 @@ | **Flame** | 自托管仪表盘 | [🔗](https://github.com/pawelmalak/flame) | 开源免费 | | **SUI** | 简单用户界面 | [🔗](https://github.com/jeroenpardon/sui) | 开源免费 | +
- -### 🌟 社区支持 - - +
+💬 社区 | 平台 | 账号/群组 | 链接 | |------|-----------|------| @@ -87,136 +134,41 @@ | **QQ群** | 647605169 | 💬 加入讨论 | | **微信群** | dxyxddsbds(备注加群) | 📱 添加微信入群 | - - -> 💡 **需要新图标?** [点击这里提交请求](https://github.com/xushier/HD-Icons/issues/new/choose) 🎯 - -## 📖 使用说明(三种方式) - -### 🐳 Docker 部署图标展示容器使用(强烈推荐) - -> 🚀 **项目地址**:[HD-Icons-docker](https://github.com/xushier/HD-Icons-docker) -> -> 💡 **优势**:自动同步更新、一键复制、移动端适配、自定义上传 - -#### 🌟 功能展示 - - - -| 功能 | 预览 | -|------|------| -| **☀️ 日间模式** | 日间模式 | -| **🌙 夜间模式** | 夜间模式 | -| **📱 移动端适配** | 移动端自适应 | -| **📋 一键复制** | 单击复制地址 | -| **📤 自定义上传** | 自定义图片上传 | - - - -### 🔗 远程链接使用(自动同步更新) - -#### 📋 GitHub 原始链接 - -> 🌐 **适用场景**:可直接访问 GitHub 的用户 -> -> 📝 **格式**:`https://raw.githubusercontent.com/xushier/HD-Icons/main/border-radius/图标名称.png` -> -> 🔗 **项目地址**:[HD-Icons](https://github.com/xushier/HD-Icons) - -#### ⚡ CDN 加速链接 - -> 🚀 **适用场景**:无法直接访问 GitHub 但需要使用 GitHub 图标源的用户 -> -> 📝 **格式**:`https://cdn.jsdelivr.net/gh/xushier/HD-Icons/border-radius/图标名称.png` -> -> 💡 **优势**:全球 CDN 加速,访问速度更快 - -> 📌 **使用提示**:将上述链接中的 `图标名称` 替换为实际图标文件名即可。[📋 查看所有图标](#-图标预览) - -### 📱 移动应用使用 - -> 🎯 **支持应用**:Yamby、Hills 等安卓 APP -> -> 📦 **图标包地址**:`https://raw.githubusercontent.com/xushier/HD-Icons/main/icons.json` -> -> ⚠️ **注意**:如无响应,请开启代理环境或自行部署 -> -> 🚀 **自部署方案**:[HD-Icons-docker](https://github.com/xushier/HD-Icons-docker) - -## ✨ 图标预览 - -> 🎨 **持续更新中**:当前共计 1754 个,数量不断增加,欢迎提交新图标请求 -### 📦 圆角矩形图标 -
- 圆角矩形图标集合 -
- -### ⭕ 圆形图标 -
- 圆形图标集合 -
- -### 🎨 SVG 矢量图标 -
- - - - -9kuai-1 actual-1 acunetix-1 adguard-home-1 adminer-1 airflow-1 airflow-2 airflow-3 ali-cloud-1 alist-1 amule-1 anaconda-1 ani-rss-1 apache-1 apache-2 apache-3 apple-tv-plus-1 aqua-1 arcane-1 arch-1 atuin-1 audi-1 audi-2 audi-3 audi-4 audi-5 audio-bookshelf-1 authelia-1 authelia-2 authentik-1 autobrr-1 backrest-1 backrest-2 baidu-1 bard-1 baserow-1 bazarr-1 benq-1 benq-2 benq-3 bentley-1 bentley-2 bigdata-tools-1 bilibili-1 bililive-recorder-1 bitwarden-1 bitwarden-2 blinko-1 blossom-1 bmw-1 bmw-2 bmw-3 bmw-4 bmw-5 bmw-6 bmw-7 bracket-1 buick-1 buick-2 buick-3 buick-4 buick-5 buick-6 burger-king-1 burger-king-2 byd-1 byd-2 byd-3 byte-base-1 c-1 c-plus-1 c-plus-plus-1 caddy-1 cal-com-1 calibre-web-1 canon-1 canon-2 canon-3 canon-4 casaos-1 centos-1 centos-2 certimate-1 chatgpt-1 chatgpt-2 chevereto-1 chevrolet-1 chevrolet-2 chevrolet-3 chevrolet-4 chevrolet-5 chrome-1 cisco-1 claper-1 clion-1 cloud-beaver-1 cloud-beaver-2 cloudflare-1 cloudflare-2 cloudreve-1 code-server-1 code-with-me-1 codex-docs-1 cooler-control-1 couch-base-1 couch-base-2 css-1 css-2 css-3 cyberchef-1 cyberchef-2 databasus-1 datagrip-1 datalore-1 dataspell-1 dawarich-1 debian-1 debian-2 deepin-1 deepseek-1 dell-1 deluge-1 directus-1 directus-2 discord-1 django-1 django-2 docker-1 docker-2 docker-3 docker-4 docker-registry-1 docspell-1 dootask-1 doris-1 dotcover-1 dotmemory-1 dotpeek-1 dottrace-1 dozzle-1 drawio-1 dumb-assets-1 duplicati-1 elastic-search-1 elastic-search-2 element-1 epson-1 epson-2 epson-3 etherpad-1 fanta-1 fanta-2 fanta-3 fanta-4 fanta-5 fanta-6 feather-wiki-1 fenrus-1 fiat-1 fiat-2 fiat-3 filerise-1 filerise-2 filerise-3 flaresolverr-1 fleet-1 flink-1 flink-2 fmd-server-1 focal-board-1 folder-1 forgejo-1 gcore-1 git-1 git-2 gitee-1 gitlab-1 glances-1 glances-2 glances-3 glances-4 goland-1 golang-1 golang-2 gopeed-1 gree-1 gree-2 grimoire-1 hadoop-1 hadoop-2 hd-icons-1 hedgedoc-1 hetzner-1 heyform-1 hisense-1 hisense-2 hive-1 hoarder-1 home-gallery-1 homebox-1 homer-1 honda-1 honda-2 honda-3 honda-4 honda-5 honor-1 huawei-1 huawei-2 huawei-3 huntarr-1 hypermind-1 hyundai-1 hyundai-2 hyundai-3 hyundai-4 intellij-idea-1 ipw-cn-1 iqiyi-1 iqiyi-2 iqiyi-3 iqoo-1 it-tools-1 java-1 java-2 java-3 javascript-1 javascript-2 jfa-go-1 jfa-go-2 jiedian-xiaobao-1 jmalcloud-1 jquery-1 jquery-2 jquery-3 jquery-4 jsr-1 jupyter-2 kfc-1 kfc-2 kfc-3 kfc-4 koel-1 kopia-1 kotlin-1 kotlin-2 ktor-1 lamborghini-1 lamborghini-2 lamborghini-3 lamborghini-4 lamborghini-5 laravel-1 leica-1 leica-2 leica-3 leica-4 leichi-1 lg-1 lg-2 lg-3 lg-4 li-1 li-2 librespeed-1 lime-survey-1 linkding-1 listmonk-1 loggit-1 lol-esports-1 lrc-api-1 luckin-coffee-1 luckin-coffee-2 luckin-coffee-3 luckin-coffee-4 luckin-coffee-5 lynx-1 mafl-1 manticore-search-1 mastodon-1 mastodon-2 mathesar-1 mautic-1 mazda-1 mazda-2 mcdonalds-1 mcdonalds-2 mcdonalds-3 mdc-ng-1 mdc-ng-2 mediawiki-1 meili-search-1 mercedes-benz-1 mercedes-benz-2 mercedes-benz-3 mercedes-benz-4 mere-medical-1 message-push-nest-1 metabase-1 metacube-xd-1 microsoft-sql-server-1 microsoft-sql-server-2 microtalk-p2p-1 microtalk-sfu-1 mind-wendel-1 mindsdb-1 mini-serve-1 mongotv-1 mongotv-2 moodle-1 mps-1 msm-1 n8n-1 namecheap-ddns-updater-1 nestjs-1 new-api-1 news-now-1 nexterm-1 nextjs-1 nextjs-2 nextjs-3 nezha-1 nginx-1 nginx-2 nginx-3 nikon-1 nikon-2 nikon-3 nikon-4 nio-1 nio-2 nio-3 nissan-1 nissan-2 nissan-3 nissan-4 nodejs-1 nodejs-2 nodejs-3 nodejs-4 notabase-1 notemark-1 nut-1 nvidia-1 oauth2proxy-1 ollama-1 one-kvm-1 onestrm-1 open-metadata-1 open-webui-1 openlist-1 opentofu-1 oppo-1 oracle-1 oracle-2 oracle-corporation-1 orb-net-1 origin-1 origin-2 orion-visor-1 outline-1 oxi-cloud-1 padloc-1 pandas-1 pangolin-1 paperless-1 paramount-1 paramount-2 paramount-3 paramount-plus-1 perl-1 perl-2 perl-3 perlite-1 photopea-1 php-1 php-2 phpstorm-1 plex-1 plex-2 plex-3 porsche-1 porsche-2 porsche-3 porsche-4 porsche-5 porsche-6 ptools-1 pulsarr-1 pycharm-1 python-1 python-2 python-3 qi-reader-1 qnap-1 qnap-2 qodana-1 qqlive-1 quark-1 quill-1 radarr-1 read-the-docs-1 readeck-1 readeck-2 realme-1 realme-2 redmi-1 resharper-1 resharperc-plus-1 rider-1 riderflow-1 riot-games-1 rocky-1 rog-1 rubymine-1 rustrover-1 rxresume-1 samsung-1 samsung-2 samsung-3 scala-1 semaphore-1 servas-1 shadcn-ui-1 smart-strm-1 snapdrop-1 sonatype-1 sonatype-nexus-repository-1 sonatype-nexus-repository-2 sony-1 sony-2 sony-3 sony-digital-1 sony-music-1 sony-pictures-1 sony-walkman-1 sony-walkman-2 sony-walkman-3 sony-walkman-4 splayer-1 squoosh-1 starbucks-coffee-1 starbucks-coffee-2 starbucks-coffee-3 stash-1 steam-1 steam-2 steam-3 steam-4 sunpanel-1 superset-1 superset-2 superset-3 superset-4 superset-5 superset-6 superset-7 swing-music-1 synctv-1 synctv-2 tailchat-1 taosync-1 tcl-1 tcl-2 teable-1 team-mapper-1 team-pass-1 telegram-1 telegram-2 telegram-3 termix-1 tesla-1 tesla-2 tesla-3 the-lounge-1 thunderbird-1 tongyi-qianwen-1 toolbox-1 toyota-1 toyota-2 toyota-3 traccar-1 typescript-1 ubuntu-1 ubuntu-2 ubuntu-3 unbalance-1 uniqlo-1 unlock-music-1 unraid-1 uptime-kuma-1 v2raya-1 vagrant-1 vertex-1 vertex-2 virola-1 vitejs-1 vivo-1 vivo-2 vivo-3 vmware-1 vscode-1 vscode-2 vscodium-1 vscodium-2 vuetify-1 wallabag-1 wallabag-2 wallabag-3 wallos-1 watchtower-1 wbo-1 webstorm-1 wechat-1 wechat-2 weclone-1 wekan-1 wekan-2 whisparr-1 wikijs-1 willow-1 windows-10-1 windows-7-1 windows-8-1 windows-95-1 windows-server-1 wireguard-1 wise-mapping-1 wordpress-1 writerside-1 xiaomi-1 xiaomi-2 xiaomi-3 youku-1 youku-2 youku-3 youtrack-1 youtube-1 youtube-2 youtube-3 youtube-4 youtube-5 zfile-1 zigbee-mqtt-1 zimaos-1 zulip-1 zulip-2 -
- - - - ---- +
## 🤝 支持与赞助
-

!!!项目批量使用请告知!!!

-

💝 感谢您的支持,让这个项目持续发展!

- - - - - -
- 支付宝赞助 -

支付宝

-
- 微信赞助 -

微信支付

-
+**!!!项目批量使用请告知!!!** + +**💝 感谢您的支持,让这个项目持续发展!** + +| 支付宝 | 微信支付 | +|--------|----------| +| 支付宝赞助 | 微信赞助 | + +赞助时请备注「图标」,感谢您的慷慨支持! -

赞助时请备注「图标」,感谢您的慷慨支持!

-## 📜 免责声明 +
+📜 免责声明 > ⚖️ **法律声明**:本仓库中图像的(几乎)所有产品名称、商标和注册商标均为其各自所有者的财产。仪表盘导航用户仅将本仓库中的所有图像用于识别目的。 -> +> > 📝 **使用说明**:这些图像文件中出现的名称、商标和品牌的使用不表示认可。 ---- +
+ +## ⭐ Star History
-### 🌟 项目统计 - [![Star History Chart](https://api.star-history.com/svg?repos=xushier/HD-Icons&type=Date)](https://star-history.com/#xushier/HD-Icons&Date) -### 📊 项目活跃度 +如果这个项目对您有帮助,请给个 ⭐ Star 支持一下! -![GitHub commit activity](https://img.shields.io/github/commit-activity/m/xushier/HD-Icons?style=for-the-badge&logo=github) -![GitHub contributors](https://img.shields.io/github/contributors/xushier/HD-Icons?style=for-the-badge&logo=github) +Made with ❤️ by xushier
- ---- - -
-

🎯 如果这个项目对您有帮助,请给个 ⭐ Star 支持一下!

-

Made with ❤️ by xushier

-
- diff --git a/_TEMPLATE.md b/_TEMPLATE.md deleted file mode 100644 index 0f3fe57..0000000 --- a/_TEMPLATE.md +++ /dev/null @@ -1,222 +0,0 @@ -
- logo -

HD-Icons:高清仪表盘图标

-

1024×1024 超清分辨率 · 无损压缩优化 · 多种样式适配

-
- - - -
- - [![GitHub stars](https://img.shields.io/github/stars/xushier/HD-Icons?style=for-the-badge&logo=github&color=ff6b6b)](https://github.com/xushier/HD-Icons/stargazers) - [![GitHub forks](https://img.shields.io/github/forks/xushier/HD-Icons?style=for-the-badge&logo=github&color=4ecdc4)](https://github.com/xushier/HD-Icons/network) - [![GitHub issues](https://img.shields.io/github/issues/xushier/HD-Icons?style=for-the-badge&logo=github&color=45b7d1)](https://github.com/xushier/HD-Icons/issues) - [![GitHub license](https://img.shields.io/github/license/xushier/HD-Icons?style=for-the-badge&logo=github&color=96ceb4)](https://github.com/xushier/HD-Icons/blob/master/LICENSE) - - - [![GitHub release](https://img.shields.io/github/release/xushier/HD-Icons?style=for-the-badge&logo=github&color=ffd93d)](https://github.com/xushier/HD-Icons/releases) - [![GitHub last commit](https://img.shields.io/github/last-commit/xushier/HD-Icons?style=for-the-badge&logo=github&color=6c5ce7)](https://github.com/xushier/HD-Icons/commits/main) - [![GitHub repo size](https://img.shields.io/github/repo-size/xushier/HD-Icons?style=for-the-badge&logo=github&color=a29bfe)](https://github.com/xushier/HD-Icons) - - - [![jsDelivr hits](https://data.jsdelivr.com/v1/package/gh/xushier/HD-Icons/badge?style=rounded)](https://www.jsdelivr.com/package/gh/xushier/HD-Icons) - -
- -
- - -
- 📖 项目简介 • - 🚀 使用说明 • - ✨ 图标预览 • - 🎯 请求图标 -
- - -
- GitHub activity -
- -
- - - - -## 📝 项目简介 - -> 🎯 **使命**:为 Unraid Docker 容器和各类仪表盘应用提供高质量、标准化的图标解决方案 - -### ✨ 核心特性 - -| 特性 | 描述 | -|------|-----| -| 🖼️ **超清分辨率** | 1024×1024 像素,确保在任何尺寸下都清晰锐利 | -| 🗜️ **无损压缩** | 所有图标经过无损压缩,体积更小,质量不变 | -| 🎨 **优化显示** | 图标主体适当放大,满足各种使用场景 | -| 📁 **多样样式** | 提供 `border-radius`(圆角矩形)、 `circle`(圆形)和 `svg`(矢量)三种风格 | -| 🔄 **持续更新** | 不定期添加新图标,满足不断增长的需求 | - -### 🎯 适用场景 - -本项目最初为 `Unraid Docker` 容器图标展示而设计,现已扩展支持多种仪表盘应用、部分APP及其他用途: - - - -| 应用程序 | 描述 | 链接 | 备注 | -|----------|------|------|------| -| **FlatNas** | 新晋现代化仪表盘 | [🔗](https://github.com/Garry-QD/FlatNas) | 开源免费 | -| **Sun-Panel** | 适合国人体质的现代化仪表盘 | [🔗](https://github.com/hslr-s/sun-panel) | 1.3.0及之前版本开源,新版Pro授权99永久 | -| **Dashy** | 现代化仪表盘 | [🔗](https://github.com/Lissy93/dashy) | 开源免费 | -| **Homer Dashboard** | 简洁的静态主页 | [🔗](https://github.com/bastienwirtz/homer) | 开源免费 | -| **Heimdall** | 应用程序仪表盘 | [🔗](https://github.com/linuxserver/Heimdall) | 开源免费 | -| **Organizr(v2)** | 组织管理工具 | [🔗](https://github.com/causefx/Organizr) | 开源免费 | -| **Flame** | 自托管仪表盘 | [🔗](https://github.com/pawelmalak/flame) | 开源免费 | -| **SUI** | 简单用户界面 | [🔗](https://github.com/jeroenpardon/sui) | 开源免费 | - - - -### 🌟 社区支持 - - - -| 平台 | 账号/群组 | 链接 | -|------|-----------|------| -| **B站** | 小迪课代表 | [🎬 传送门](https://space.bilibili.com/32313260) | -| **公众号** | 小迪同学 | 📱 微信搜索关注 | -| **QQ群** | 647605169 | 💬 加入讨论 | -| **微信群** | dxyxddsbds(备注加群) | 📱 添加微信入群 | - - - -> 💡 **需要新图标?** [点击这里提交请求](https://github.com/xushier/HD-Icons/issues/new/choose) 🎯 - -## 📖 使用说明(三种方式) - -### 🐳 Docker 部署图标展示容器使用(强烈推荐) - -> 🚀 **项目地址**:[HD-Icons-docker](https://github.com/xushier/HD-Icons-docker) -> -> 💡 **优势**:自动同步更新、一键复制、移动端适配、自定义上传 - -#### 🌟 功能展示 - - - -| 功能 | 预览 | -|------|------| -| **☀️ 日间模式** | 日间模式 | -| **🌙 夜间模式** | 夜间模式 | -| **📱 移动端适配** | 移动端自适应 | -| **📋 一键复制** | 单击复制地址 | -| **📤 自定义上传** | 自定义图片上传 | - - - -### 🔗 远程链接使用(自动同步更新) - -#### 📋 GitHub 原始链接 - -> 🌐 **适用场景**:可直接访问 GitHub 的用户 -> -> 📝 **格式**:`https://raw.githubusercontent.com/xushier/HD-Icons/main/border-radius/图标名称.png` -> -> 🔗 **项目地址**:[HD-Icons](https://github.com/xushier/HD-Icons) - -#### ⚡ CDN 加速链接 - -> 🚀 **适用场景**:无法直接访问 GitHub 但需要使用 GitHub 图标源的用户 -> -> 📝 **格式**:`https://cdn.jsdelivr.net/gh/xushier/HD-Icons/border-radius/图标名称.png` -> -> 💡 **优势**:全球 CDN 加速,访问速度更快 - -> 📌 **使用提示**:将上述链接中的 `图标名称` 替换为实际图标文件名即可。[📋 查看所有图标](#-图标预览) - -### 📱 移动应用使用 - -> 🎯 **支持应用**:Yamby、Hills 等安卓 APP -> -> 📦 **图标包地址**:`https://raw.githubusercontent.com/xushier/HD-Icons/main/icons.json` -> -> ⚠️ **注意**:如无响应,请开启代理环境或自行部署 -> -> 🚀 **自部署方案**:[HD-Icons-docker](https://github.com/xushier/HD-Icons-docker) - -## ✨ 图标预览 - -> 🎨 **持续更新中**:当前共计 0 个,数量不断增加,欢迎提交新图标请求 - -### 📦 圆角矩形图标 -
- 圆角矩形图标集合 -
- -### ⭕ 圆形图标 -
- 圆形图标集合 -
- -### 🎨 SVG 矢量图标 -
- - - - - -
- - - - ---- - -## 🤝 支持与赞助 - -
-

!!!项目批量使用请告知!!!

-

💝 感谢您的支持,让这个项目持续发展!

- - - - - - -
- 支付宝赞助 -

支付宝

-
- 微信赞助 -

微信支付

-
- -

赞助时请备注「图标」,感谢您的慷慨支持!

-
- -## 📜 免责声明 - -> ⚖️ **法律声明**:本仓库中图像的(几乎)所有产品名称、商标和注册商标均为其各自所有者的财产。仪表盘导航用户仅将本仓库中的所有图像用于识别目的。 -> -> 📝 **使用说明**:这些图像文件中出现的名称、商标和品牌的使用不表示认可。 - ---- - -
- -### 🌟 项目统计 - -[![Star History Chart](https://api.star-history.com/svg?repos=xushier/HD-Icons&type=Date)](https://star-history.com/#xushier/HD-Icons&Date) - -### 📊 项目活跃度 - -![GitHub commit activity](https://img.shields.io/github/commit-activity/m/xushier/HD-Icons?style=for-the-badge&logo=github) -![GitHub contributors](https://img.shields.io/github/contributors/xushier/HD-Icons?style=for-the-badge&logo=github) - -
- ---- - -
-

🎯 如果这个项目对您有帮助,请给个 ⭐ Star 支持一下!

-

Made with ❤️ by xushier

-
diff --git a/_generate.py b/_generate.py deleted file mode 100644 index b12d21e..0000000 --- a/_generate.py +++ /dev/null @@ -1,53 +0,0 @@ -import pathlib -from pathlib import Path - -root = pathlib.Path(__file__).parent.resolve() -template_path = root / "_TEMPLATE.md" -readme_path = root / "README.md" - - -# def generate_img_tag(file,folder,radius): - # return f'
{file.stem}
{file.stem}
' - -def generate_img_tag(file,folder): - return f'{file.stem}' - -imgs = sorted(Path("./border-radius").glob("*.png")) -img_tags = [generate_img_tag(x,"border-radius") for x in imgs] -circle_imgs = sorted(Path("./circle").glob("*.png")) -circle_img_tags = [generate_img_tag(x,"circle") for x in circle_imgs] -svg_imgs = sorted(Path("./svg").glob("*.svg")) -svg_img_tags = [generate_img_tag(x,"svg") for x in svg_imgs] -all_nums = len(img_tags) + len(circle_img_tags) + len(svg_img_tags) - -# Read the template file -with open(template_path, "r", encoding="UTF-8") as f: - lines = f.readlines() - -# Find the line that starts with "" -# for line in lines: -# if line.startswith(""): -# line_number = lines.index(line) -# break -# for line in lines: -# if line.startswith(""): -# circle_line_number = lines.index(line) -# break -for line in lines: - if line.startswith(""): - svg_line_number = lines.index(line) - break - -# Insert the icons after the line -# lines.insert(line_number + 1, " ".join(img_tags)) -# lines.insert(circle_line_number + 2, " ".join(circle_img_tags)) -lines.insert(svg_line_number + 3, " ".join(svg_img_tags)) - -lines = ["> 🎨 **持续更新中**:当前共计 " + str(all_nums) + " 个,数量不断增加,欢迎提交新图标请求" if '> 🎨 **持续更新中**:当前共计 0 个,数量不断增加,欢迎提交新图标请求' in i else i for i in lines] - -# Write the new file -with open(readme_path, "w", encoding="UTF-8") as f: - f.write("".join(lines)) - f.write("\n") - -print("文件已更新!") diff --git a/_icons-circle.jpg b/_icons-circle.jpg index ab554c8..71f8dff 100644 Binary files a/_icons-circle.jpg and b/_icons-circle.jpg differ diff --git a/_icons-radius.jpg b/_icons-radius.jpg index af73dbd..12f32c0 100644 Binary files a/_icons-radius.jpg and b/_icons-radius.jpg differ diff --git a/icons.json b/icons.json index 4a76dc7..63d984b 100644 --- a/icons.json +++ b/icons.json @@ -1,8 +1,8 @@ { "name": "小迪的HD-Icons", - "description": "当前数量:1754,更新于:2026-02-01 21:43:36。不定期更新,有需求欢迎提交:github.com/xushier/HD-Icons", + "description": "当前数量:1754,更新于:2026-08-27 19:06:22。不定期更新,有需求欢迎提交:github.com/xushier/HD-Icons", "total_count": 1754, - "update_at": "2026-02-01 21:43:36", + "update_at": "2026-08-27 19:06:22", "icons": [ { "name": "115-drive-1", @@ -7021,4 +7021,4 @@ "url": "https://raw.githubusercontent.com/xushier/HD-Icons/main/svg/zulip-2.svg" } ] -} \ No newline at end of file +} diff --git a/inbox/border-radius/.gitkeep b/inbox/border-radius/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/inbox/circle/.gitkeep b/inbox/circle/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/inbox/svg/.gitkeep b/inbox/svg/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/publish.bat b/publish.bat new file mode 100644 index 0000000..4888e28 --- /dev/null +++ b/publish.bat @@ -0,0 +1,4 @@ +@echo off +chcp 65001 >nul +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0publish.ps1" %* +pause diff --git a/publish.ps1 b/publish.ps1 new file mode 100644 index 0000000..ac74ecb --- /dev/null +++ b/publish.ps1 @@ -0,0 +1,52 @@ +# HD-Icons 一键发布脚本 +# 用法:把新图标放入 inbox/ 对应子文件夹后,双击 publish.bat(或运行本脚本) +# 可选参数:.\publish.ps1 -Message "自定义提交说明" + +param([string]$Message = "") + +$ErrorActionPreference = "Stop" +Set-Location $PSScriptRoot + +# 定位 git(git 不在 PATH 时使用常见安装路径) +$git = "git" +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + $fallback = "C:\Program Files\Git\cmd\git.exe" + if (Test-Path $fallback) { $git = $fallback } else { + Write-Host "[错误] 未找到 git,请安装 Git 或将其加入 PATH" -ForegroundColor Red + exit 1 + } +} + +# 检查 inbox 是否有新文件 +$inboxStatus = & $git status --porcelain -- inbox +if (-not $inboxStatus) { + Write-Host "inbox 中没有新图标,无需发布。" -ForegroundColor Yellow + exit 0 +} + +# 从文件名自动生成提交说明 +$names = @($inboxStatus | ForEach-Object { + $_.Substring(3).Trim() -replace '^inbox/', '' +} | ForEach-Object { [System.IO.Path]::GetFileNameWithoutExtension($_) -replace '-\d+$', '' } | Sort-Object -Unique) +$prefixes = ($names | Select-Object -First 8) -join ", " +if ($names.Count -gt 8) { $prefixes += " 等" } +$fileCount = ($inboxStatus | Measure-Object).Count +if (-not $Message) { + $Message = "新增 $fileCount 个图标:$prefixes" +} + +Write-Host "本次发布:$Message" -ForegroundColor Cyan +& $git add -A +& $git commit -m $Message +if ($LASTEXITCODE -ne 0) { + Write-Host "[错误] 提交失败" -ForegroundColor Red + exit 1 +} +& $git push +if ($LASTEXITCODE -ne 0) { + Write-Host "[错误] 推送失败,请检查网络或凭据" -ForegroundColor Red + exit 1 +} +Write-Host "" +Write-Host "已推送到 GitHub,Actions 将自动完成压缩、入库、索引、README 与预览图更新。" -ForegroundColor Green +Write-Host "进度查看:https://github.com/xushier/HD-Icons/actions" diff --git a/scripts/build.py b/scripts/build.py new file mode 100644 index 0000000..497d7cd --- /dev/null +++ b/scripts/build.py @@ -0,0 +1,409 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +HD-Icons 一键构建脚本(本地 / GitHub Actions 通用) + +流程: + 1. 校验 inbox 新文件命名 + 2. TinyPNG 无损压缩 inbox 中的 PNG(SVG 不压缩) + 3. 分发入库:inbox 文件移入对应目录,重名按"同前缀最大序号+1"自动改名 + 4. 全量重建 icons.json(输出格式与历史版本完全一致) + 5. 更新 README.md 中的数量标记 + 6. 重新生成三张合并预览图(_icons-radius.jpg / _icons-circle.jpg / _icons-svg.jpg) + +用法: + python scripts/build.py --repo . + +环境变量: + TINYPNG_KEY TinyPNG API 密钥(inbox 有 PNG 时必需;GitHub 上配置为 Secret) + HDICONS_FONT 预览图标签字体路径(可选,默认自动查找) +""" + +import argparse +import base64 +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile +import urllib.error +import urllib.request +from datetime import datetime +from pathlib import Path + +FOLDERS = ["border-radius", "circle", "svg"] +RAW_BASE = "https://raw.githubusercontent.com/xushier/HD-Icons/main" +IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".svg", ".gif"} + +NAME_RE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$") +NUM_SUFFIX_RE = re.compile(r"-\d+$") +README_MARKER_RE = re.compile(r"()(.*?)()") + +# 预览图排版参数 +PREVIEW = { + "icon": 128, # 单个图标缩略尺寸 + "cols": 15, # 每行图标数 + "gap_x": 30, # 水平间距 + "gap_y": 62, # 垂直间距(含文件名文字区域) + "pad": 20, # 四周留白 + "text_size": 17, # 文件名字号 + "bg": (244, 246, 249), + "fg": (62, 66, 72), +} + + +def log(msg): + print(msg, flush=True) + + +def warn(msg): + print(f"[警告] {msg}", file=sys.stderr, flush=True) + + +def fail(msg): + print(f"[错误] {msg}", file=sys.stderr, flush=True) + sys.exit(1) + + +# ---------------------------------------------------------------- 1. 校验 inbox + +def validate_inbox(repo): + """检查 inbox 内新文件的类型与命名,返回 (errors, warnings, files)。""" + errors, warnings, files = [], [], {} + for folder in FOLDERS: + inbox_dir = repo / "inbox" / folder + items = [] + if not inbox_dir.is_dir(): + files[folder] = items + continue + expected = ".svg" if folder == "svg" else ".png" + for f in sorted(inbox_dir.iterdir()): + if f.name == ".gitkeep" or not f.is_file(): + continue + if f.suffix.lower() != expected: + errors.append(f"inbox/{folder}/ 只接受 {expected} 文件,发现:{f.name}") + continue + if not NAME_RE.match(f.stem): + errors.append(f"命名不合法(仅允许小写字母/数字/连字符):{f.name}") + continue + if not NUM_SUFFIX_RE.search(f.stem): + warnings.append(f"{f.name} 未以数字结尾,建议形如 name-1 的命名") + items.append(f) + files[folder] = items + return errors, warnings, files + + +# ---------------------------------------------------------------- 2. TinyPNG 压缩 + +def tinify(path, key): + """调用 TinyPNG API 压缩单个 PNG,返回 (压缩前字节数, 压缩后字节数, 已用额度)。""" + data = path.read_bytes() + req = urllib.request.Request("https://api.tinify.com/shrink", data=data) + req.add_header("Authorization", + "Basic " + base64.b64encode(f"api:{key}".encode()).decode()) + with urllib.request.urlopen(req, timeout=180) as resp: + info = json.loads(resp.read().decode()) + quota = (resp.headers.get("Compression-Count") + or resp.headers.get("X-Compression-Count")) + with urllib.request.urlopen(info["output"]["url"], timeout=180) as r: + out = r.read() + if len(out) < len(data): + path.write_bytes(out) + return len(data), path.stat().st_size, quota + + +def compress_inbox(files, key): + saved = 0 + quota = None + pngs = files["border-radius"] + files["circle"] + for f in pngs: + try: + before, after, quota = tinify(f, key) + except urllib.error.HTTPError as e: + if e.code == 429: + fail("TinyPNG 本月免费额度已用完(500 张/月),本次未做任何改动") + fail(f"压缩失败 {f.name}:HTTP {e.code} {e.reason}") + except (urllib.error.URLError, OSError) as e: + fail(f"压缩失败 {f.name}:网络错误 {e}") + saved += before - after + log(f" {f.name}: {before // 1024}KB -> {after // 1024}KB") + msg = f"共压缩 {len(pngs)} 张,节省 {saved // 1024}KB" + if quota: + msg += f"(本月已用 {quota}/500)" + log(msg) + + +# ---------------------------------------------------------------- 3. 分发入库 + +def available_name(target_dir, name): + """若目标已存在同名文件,按"同前缀最大序号+1"改名,否则保持原名。""" + if not (target_dir / name).exists(): + return name + stem, ext = Path(name).stem, Path(name).suffix + prefix = NUM_SUFFIX_RE.sub("", stem) + max_num = 0 + for f in target_dir.iterdir(): + m = re.fullmatch(re.escape(prefix) + r"-(\d+)", f.stem) + if m and f.suffix.lower() == ext.lower(): + max_num = max(max_num, int(m.group(1))) + n = max_num + 1 + while (target_dir / f"{prefix}-{n}{ext}").exists(): + n += 1 + return f"{prefix}-{n}{ext}" + + +def dispatch(repo, files): + moved = [] + for folder, items in files.items(): + if not items: + continue + target = repo / folder + for f in items: + new_name = available_name(target, f.name) + if new_name != f.name: + log(f" 重名处理:{folder}/{f.name} -> {new_name}") + shutil.move(str(f), str(target / new_name)) + moved.append(f"{folder}/{new_name}") + return moved + + +# ---------------------------------------------------------------- 4. icons.json + +def build_icons_json(repo): + """全量重建 icons.json,逻辑与历史脚本一致(含跨目录重名加后缀的去重行为)。""" + icons, used = [], set() + counts = {"radius": 0, "circle": 0, "svg": 0} + for folder in FOLDERS: + d = repo / folder + if not d.is_dir(): + warn(f"文件夹不存在,跳过:{folder}") + continue + for file in sorted(d.iterdir()): + if not (file.is_file() and file.suffix.lower() in IMAGE_EXTS): + continue + name = file.stem + original = name + url = f"{RAW_BASE}/{folder}/{file.name}" + counter = 1 + while name in used: + name = f"{original}-{counter}" + counter += 1 + used.add(name) + icons.append({"name": name, "url": url}) + counts[{"border-radius": "radius", "circle": "circle", "svg": "svg"}[folder]] += 1 + + update_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + data = { + "name": "小迪的HD-Icons", + "description": (f"当前数量:{len(icons)},更新于:{update_at}。" + "不定期更新,有需求欢迎提交:github.com/xushier/HD-Icons"), + "total_count": len(icons), + "update_at": update_at, + "icons": icons, + } + (repo / "icons.json").write_text( + json.dumps(data, ensure_ascii=False, indent=4) + "\n", encoding="utf-8") + counts["total"] = len(icons) + return counts + + +# ---------------------------------------------------------------- 5. README 标记 + +def update_readme(repo, counts): + readme = repo / "README.md" + if not readme.is_file(): + warn("README.md 不存在,跳过数量更新") + return + text = readme.read_text(encoding="utf-8") + + def repl(m): + key = m.group(2) + if key in counts: + return m.group(1) + str(counts[key]) + m.group(4) + warn(f"README 中存在未知标记 ICONS:{key}") + return m.group(0) + + readme.write_text(README_MARKER_RE.sub(repl, text), encoding="utf-8") + + +# ---------------------------------------------------------------- 6. 预览图 + +def load_font(size): + from PIL import ImageFont + candidates = [ + os.environ.get("HDICONS_FONT"), + str(Path(__file__).resolve().parent / "fonts" / "DejaVuSans.ttf"), + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "C:/Windows/Fonts/segoeui.ttf", + "C:/Windows/Fonts/arial.ttf", + ] + for c in candidates: + if c and Path(c).is_file(): + try: + return ImageFont.truetype(c, size) + except OSError: + pass + warn("未找到可用字体,预览图将使用默认位图字体") + return ImageFont.load_default() + + +def rasterize_svg(svg_path, size, cache_dir): + """把 SVG 光栅化为 PNG(依次尝试 rsvg-convert / resvg / cairosvg),失败返回 None。""" + out = cache_dir / (svg_path.stem + ".png") + if out.exists(): + return out + cmds = [] + if shutil.which("rsvg-convert"): + cmds.append(["rsvg-convert", "-w", str(size), "-h", str(size), + "-o", str(out), str(svg_path)]) + if shutil.which("resvg"): + cmds.append(["resvg", "--width", str(size), "--height", str(size), + str(svg_path), str(out)]) + for cmd in cmds: + try: + if subprocess.run(cmd, capture_output=True, timeout=60).returncode == 0 \ + and out.exists(): + return out + except (OSError, subprocess.TimeoutExpired): + pass + try: + import cairosvg + cairosvg.svg2png(url=str(svg_path), write_to=str(out), + output_width=size, output_height=size) + if out.exists(): + return out + except Exception: + pass + return None + + +def merge_preview(repo, folder, out_name): + """把目录内全部图标合并为一张带文件名标注的 JPEG 预览图。""" + from PIL import Image, ImageDraw + import textwrap + + src = repo / folder + files = sorted(f for f in src.iterdir() + if f.is_file() and f.suffix.lower() in IMAGE_EXTS) + if not files: + warn(f"{folder}/ 为空,跳过预览图 {out_name}") + return + + font = load_font(PREVIEW["text_size"]) + cell_w = PREVIEW["icon"] + PREVIEW["gap_x"] + cell_h = PREVIEW["icon"] + PREVIEW["gap_y"] + rows = (len(files) + PREVIEW["cols"] - 1) // PREVIEW["cols"] + width = PREVIEW["cols"] * cell_w - PREVIEW["gap_x"] + 2 * PREVIEW["pad"] + height = rows * cell_h - PREVIEW["gap_y"] + 2 * PREVIEW["pad"] + + sheet = Image.new("RGB", (width, height), PREVIEW["bg"]) + draw = ImageDraw.Draw(sheet) + + cache_dir = Path(tempfile.mkdtemp(prefix="hdicons_")) + skipped = 0 + try: + for i, f in enumerate(files): + row, col = divmod(i, PREVIEW["cols"]) + x = col * cell_w + PREVIEW["pad"] + y = row * cell_h + PREVIEW["pad"] + + if f.suffix.lower() == ".svg": + raster = rasterize_svg(f, 512, cache_dir) + if raster is None: + skipped += 1 + continue + f = raster + try: + icon = Image.open(f).convert("RGBA") + except OSError as e: + warn(f"无法读取 {f.name}:{e}") + skipped += 1 + continue + icon = icon.resize((PREVIEW["icon"], PREVIEW["icon"]), + Image.Resampling.LANCZOS) + sheet.paste(icon, (x, y), icon) + + wrapped = "\n".join(textwrap.wrap(f.stem, width=16)) + bbox = draw.textbbox((0, 0), wrapped, font=font) + text_w = bbox[2] - bbox[0] + draw.text((x + (PREVIEW["icon"] - text_w) // 2, + y + PREVIEW["icon"] + 4), + wrapped, font=font, fill=PREVIEW["fg"]) + finally: + shutil.rmtree(cache_dir, ignore_errors=True) + + rendered = len(files) - skipped + if rendered < len(files): + # 预览图必须包含全部图标,有遗漏时不覆盖已有图片,避免生成残缺预览 + warn(f"{folder} 有 {skipped} 个文件未能渲染(SVG 光栅化不可用或文件损坏)," + f"本次跳过写入 {out_name},保留现有版本") + return + out_path = repo / out_name + sheet.save(out_path, format="JPEG", quality=78, dpi=(128, 128)) + log(f" {out_name}: {len(files)} 个图标,{sheet.width}x{sheet.height}") + + +# ---------------------------------------------------------------- 主流程 + +def main(): + parser = argparse.ArgumentParser(description="HD-Icons 一键构建") + parser.add_argument("--repo", default=".", help="仓库根目录") + parser.add_argument("--skip-compress", action="store_true", + help="跳过 TinyPNG 压缩(仅调试用)") + args = parser.parse_args() + repo = Path(args.repo).resolve() + + log("== 1/6 校验 inbox ==") + errors, warnings, inbox_files = validate_inbox(repo) + for w in warnings: + warn(w) + if errors: + for e in errors: + warn(e) + fail("inbox 存在问题,已中止(所有文件保持原样)") + + png_count = len(inbox_files["border-radius"]) + len(inbox_files["circle"]) + svg_count = len(inbox_files["svg"]) + total_inbox = png_count + svg_count + log(f"inbox 共 {total_inbox} 个新文件(PNG {png_count},SVG {svg_count})") + + if png_count and not args.skip_compress: + key = os.environ.get("TINYPNG_KEY", "").strip() + if not key: + fail("inbox 中有 PNG 但未设置 TINYPNG_KEY" + "(GitHub 上需在 Settings -> Secrets 中配置)") + log("== 2/6 TinyPNG 无损压缩 ==") + compress_inbox(inbox_files, key) + else: + log("== 2/6 跳过压缩(无 PNG 或指定 --skip-compress)==") + + log("== 3/6 分发入库 ==") + moved = dispatch(repo, inbox_files) + for m in moved: + log(f" + {m}") + + log("== 4/6 重建 icons.json ==") + counts = build_icons_json(repo) + log(f"总数 {counts['total']}(圆角矩形 {counts['radius']} / " + f"圆形 {counts['circle']} / SVG {counts['svg']})") + + log("== 5/6 更新 README 数量标记 ==") + update_readme(repo, counts) + + log("== 6/6 生成预览图 ==") + merge_preview(repo, "border-radius", "_icons-radius.jpg") + merge_preview(repo, "circle", "_icons-circle.jpg") + merge_preview(repo, "svg", "_icons-svg.jpg") + + gh_output = os.environ.get("GITHUB_OUTPUT") + if gh_output: + with open(gh_output, "a", encoding="utf-8") as f: + f.write(f"added={len(moved)}\n") + + log(f"完成!本次新增 {len(moved)} 个图标。") + + +if __name__ == "__main__": + main() diff --git a/scripts/fonts/DejaVuSans.ttf b/scripts/fonts/DejaVuSans.ttf new file mode 100644 index 0000000..e5f7eec Binary files /dev/null and b/scripts/fonts/DejaVuSans.ttf differ