{"id":21268760,"url":"https://github.com/wswmsword/hanav","last_synced_at":"2025-10-02T23:35:09.816Z","repository":{"id":242248853,"uuid":"804424874","full_name":"wswmsword/hanav","owner":"wswmsword","description":"纵享丝滑导航栏。A React Navigation Menu Component. Super Smooth! Super Fast! Super Accessible! 🌷🪻🌹🌻🌷","archived":false,"fork":false,"pushed_at":"2024-11-11T11:39:45.000Z","size":339,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-11T12:32:06.433Z","etag":null,"topics":["accessibility","keyboard-navigation","navigation-bar","navigation-menu","react-navbar"],"latest_commit_sha":null,"homepage":"https://wswmsword.github.io/examples/hanav","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wswmsword.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-22T15:02:22.000Z","updated_at":"2024-11-11T11:39:48.000Z","dependencies_parsed_at":"2024-11-11T12:34:35.775Z","dependency_job_id":"2f28a217-0522-4e6f-bb94-e666b9bdf627","html_url":"https://github.com/wswmsword/hanav","commit_stats":{"total_commits":66,"total_committers":1,"mean_commits":66.0,"dds":0.0,"last_synced_commit":"5f54f21d869b4105998dbce672495946d8822a9f"},"previous_names":["wswmsword/navbar-153","wswmsword/navbar-s","wswmsword/hanav"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wswmsword%2Fhanav","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wswmsword%2Fhanav/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wswmsword%2Fhanav/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wswmsword%2Fhanav/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wswmsword","download_url":"https://codeload.github.com/wswmsword/hanav/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235048996,"owners_count":18927717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accessibility","keyboard-navigation","navigation-bar","navigation-menu","react-navbar"],"created_at":"2024-11-21T08:06:06.053Z","updated_at":"2025-10-02T23:35:09.800Z","avatar_url":"https://github.com/wswmsword.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hanav\n\n\u003ca href=\"https://996.icu\"\u003e\u003cimg src=\"https://img.shields.io/badge/link-996.icu-red.svg\" alt=\"996.icu\" align=\"right\"\u003e\u003c/a\u003e\n\n中文 | [English](./README_EN.md)\n\nhanav 是一个 React 导航栏组件库，包含一组触发器和一组对应的菜单面板，用户可以通过触发器展开、切换、收起菜单面板。导航栏通常出现在网站的顶部，提供最希望用户访问的链接和其它控件。hanav 有下面这些特性：\n\n- 🍯 流畅的过渡动画；\n- 🎹 键盘导航（即将支持[空间导航](https://juejin.cn/post/7463871170015346703)）；\n- ♿️ 屏幕阅读器导航；\n- 🎨 高度自定义；\n- 📱 兼容移动端设计；\n- 🚀 开发体验良好。\n\n\u003e hanav is a React navigation menu component library that includes a set of triggers and a corresponding set of menu panels. For more information, please refer to [the English README](./README_EN.md) or [demo](https://wswmsword.github.io/examples/hanav/en).\n\n您可以打开[演示链接](https://wswmsword.github.io/examples/hanav)，查看 hanav 在不同屏幕下的使用效果，或[在线编辑 CodeSandbox](https://codesandbox.io/p/sandbox/rn6r6d)（[![Edit hanav-demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/rn6r6d)），及时看到修改效果。\n\n\u003cdetails\u003e\n\u003csummary\u003e在 Chrome 中，可以打开“短暂地突出显示焦点对象”无障碍功能，来可视化查看组件的焦点走向。\u003c/summary\u003e\n\n在地址栏输入 `chrome://settings/accessibility`，或者在“设置 -\u003e 无障碍”中，可以设置“短暂地突出显示焦点对象”。\n\n![Chrome Outer Row](./images/chrome-outer-row.png)\n\n\u003c/details\u003e\n\n## 安装和使用\n\n使用 npm 安装 hanav：\n\n```bash\nnpm install hanav\n```\n\n下面是安装之后，使用组件的最简形态，更精美的范例可以打开[仓库的 `dark-space` 文件夹](./examples/dark-space/components/header/nav.jsx)（Next.js 项目）查看：\n\n```javascript\nimport { NavBar, Trigger, Item, Content } from \"hanav\";\nexport default function MyNavBar() {\n  return \u003cNavBar style={{ position: \"relative\" }}\u003e\n    \u003cTrigger style={{ display: \"flex\", gap: 8 }}\u003e\n      \u003ca href=\"https://github.com/wswmsword/hanav\"\u003eRepo\u003c/a\u003e\n      \u003cItem\u003e\u003cbutton\u003eTrigger 1\u003c/button\u003e\u003c/Item\u003e\n      \u003cItem\u003e\u003cbutton\u003eTrigger 2\u003c/button\u003e\u003c/Item\u003e\n      \u003cItem\u003e\u003cbutton\u003eTrigger 3\u003c/button\u003e\u003c/Item\u003e\n    \u003c/Trigger\u003e\n    \u003cContent className=\"panelsWrapper\"\u003e\n      \u003cItem\u003e\u003cdiv\u003eContent 1\u003c/div\u003e\u003c/Item\u003e\n      \u003cItem\u003e\u003cdiv\u003e\n        \u003ca href=\"https://react.dev/?uwu\"\u003eReact\u003c/a\u003e vs\n        \u003ca href=\"https://vuejs.org/?uwu\"\u003eVue\u003c/a\u003e\n      \u003c/div\u003e\u003c/Item\u003e\n      \u003cItem\u003e\u003cdiv\u003eContent 3\u003c/div\u003e\u003c/Item\u003e\n    \u003c/Content\u003e\n  \u003c/NavBar\u003e;\n}\n```\n\n一般，上面的范例更适合桌面端之类的宽屏，移动端使用 hanav 的大致形态可以查看后面的“[移动端视图 mini 系列](#移动端视图-mini-系列)”一节，也可以打开仓库的 [`dark-space` 文件夹](./examples/dark-space/components/header/mini-nav.jsx)查看完整例子。\n\n## API\n\n导航栏组件主要由 4 部分组成，分别是 `\u003cNavBar\u003e`、`\u003cTrigger\u003e`、`\u003cContent\u003e` 和 `\u003cItem\u003e`，此外，`\u003cContent\u003e` 还包括一些变体用于满足**关闭**或**定制**过渡动画的需求。\n\n`\u003cHead\u003e` 和 `\u003cTail\u003e` 用于标记每个菜单面板中可被聚焦的首尾元素，用于**优化**键盘导航。\n\n对于移动端视图，hanav 提供了 mini 系列，包括 `\u003cMiniNavBar\u003e`、`\u003cMiniTrigger\u003e`、`\u003cMiniContent\u003e`、`\u003cMiniItem\u003e`、`\u003cMiniMenu\u003e`、`\u003cMiniToggle\u003e`、`\u003cMiniBack\u003e`。\n\n### NavBar\n\n导航栏组件的最外层组件，使用的时候具名导入，例如：\n\n```javascript\nimport { NavBar } from \"hanav\";\n```\n\n`\u003cNavBar\u003e` 会被渲染成 `\u003cnav\u003e` 作为导航栏组件的最外层，`\u003cNavBar\u003e` 接收任何用于 HTML 元素的 props，以及下面这些额外选项：\n\n- `dur`，number，定义过渡动画的持续时间（s）；\n- `gap`，number，设置面板和触发器之间的距离（px）；\n- `dynamicWidth`，boolean，允许面板的宽度变化；\n- `onlyKeyFocus`，boolean，设置焦点仅在键盘控制时触发转移；\n- `close`，boolean|number，切换面板时跟随触发器的位置。\n\n### Trigger\n\n像下面这样导入 `\u003cTrigger\u003e` 组件：\n\n```javascript\nimport { Trigger } from \"hanav\";\n```\n\n`\u003cTrigger\u003e` 会被渲染成 `\u003cdiv\u003e`，作为 `\u003cnav\u003e` 的子元素，`\u003cTrigger\u003e` 接收任何内置的 props。`\u003cTrigger\u003e` 组件内部是一组触发器，因此可以在 `\u003cTrigger\u003e` 上传入 `className` 或 `style` 来定义触发器的布局。\n\n### Content\n\n```javascript\nimport { Content } from \"hanav\";\n```\n\n`\u003cContent\u003e` 组件内部是一组内容面板，每一个内容面板都按顺序对应了 `\u003cTrigger\u003e` 组件内部的触发器，`\u003cContent\u003e` 与 `\u003cTrigger\u003e` 需要是兄弟节点，`\u003cContent\u003e` 组件会被渲染成两层 `\u003cdiv\u003e`，内层 `\u003cdiv\u003e` 用于纵轴动画，外层 `\u003cdiv\u003e` 用于*整个面板*的横轴动画。\n\n`\u003cContent\u003e` 接收任何内置的 props，这些 props 最终生效在**内层** `\u003cdiv\u003e` 上，外层 `\u003cdiv\u003e` 可以通过 `outer` 属性传入需要的 props。内层 `\u003cdiv\u003e` 用于设置整个面板的样式，外层 `\u003cdiv\u003e` 主要用于 hanav 内部对整个面板横向动画的控制。\n\n- `outer`，`outer` 中的对象会作为 props 传入 `\u003cContent\u003e` 渲染的外层 `\u003cdiv\u003e` 上；\n- `onExpanding`，`() =\u003e void`，菜单展开动画开始时调用；\n- `onExpanded`，`() =\u003e void`，展开动画结束后调用；\n- `onCollapsing`，`() =\u003e void`，收起动画开始时调用；\n- `onCollapsed`，`() =\u003e void`，收起动画结束后调用。\n\n### Item\n\n```javascript\nimport { Item } from \"hanav\";\n```\n\n`\u003cItem\u003e` 必须作为 `\u003cTrigger\u003e` 或 `\u003cContent\u003e` 的直接子元素，`\u003cItem\u003e` 在 `\u003cTrigger\u003e` 中是触发器，在 `\u003cContent\u003e` 中是内容面板，`\u003cItem\u003e` 不接收任何参数。\n\n触发器和内容面板成双成对，因此 `\u003cTrigger\u003e` 和 `\u003cContent\u003e` 中的 `\u003cItem\u003e` 数量相等。\n\n`\u003cTrigger\u003e` 中 `\u003cItem\u003e` 的内容可以是一个组件或元素，也可以是一个 render prop：\n\n```javascript\n// 组件/元素\n\u003cItem\u003e\u003cbutton\u003eTrigger 1\u003c/button\u003e\u003c/Item\u003e\n// render prop\n\u003cItem\u003e{(props, isOpen) =\u003e \u003cbutton {...props}\u003eTrigger 1\u003c/button\u003e}\u003c/Item\u003e\n```\n\nrender prop 的方式也许对于代码的理解更有帮助，但是不如直接传入组件简洁。render prop 的第一个入参包含了事件、ARIA 标签等必要信息，第二个入参表示展开或收起的状态。\n\n`\u003cItem\u003e` 在 `\u003cContent\u003e` 中时，`\u003cItem\u003e` 的子元素是一个内容面板，子元素 children 同样可以是一个组件/元素，也可以是一个 render prop：\n\n```javascript\n// 组件/元素\n\u003cItem\u003e\u003cdiv\u003e\n  \u003ca href=\"https://react.dev/?uwu\"\u003eReact\u003c/a\u003e vs\n  \u003ca href=\"https://vuejs.org/?uwu\"\u003eVue\u003c/a\u003e\n\u003c/div\u003e\u003c/Item\u003e\n// render prop\n\u003cItem\u003e\n  {(props, head, tail) =\u003e \u003cdiv {...props} style={{ ...props.style, width: \"100%\", flexShrink: 0 }}\u003e\n    \u003ca href=\"https://react.dev/?uwu\" ref={head}\u003eReact\u003c/a\u003e vs\n    \u003ca href=\"https://vuejs.org/?uwu\" ref={tail}\u003eVue\u003c/a\u003e\n  \u003c/div\u003e}\n\u003c/Item\u003e\n```\n\nhanav 需要知晓菜单面板中的首尾**可聚焦元素**，以此完成键盘导航。从上面的例子可以看到，render prop 形式的子元素提供了 2、3 参数，使用 `ref` 标记首尾可聚焦元素。组件/元素形式的子元素可以通过引入 `\u003cHead/Tail\u003e` 组件来声明式标记首尾可聚焦元素。\n\n### Head/Tail\n\n```javascript\nimport { Head, Tail, MiniHead, MiniTail } from \"hanav\";\n```\n\n`\u003cHead/Tail\u003e` 用于 `\u003cContent\u003e` 下的 `\u003cItem\u003e` 子元素中，`\u003cMiniHead/MiniTail\u003e` 用于 `\u003cMiniContent\u003e` 下的 `\u003cMiniItem\u003e` 子元素中。它们都是**可选**的。\n\n它们用于标记每个菜单面板中的首尾可聚焦元素。成功标记后，按下 \u003ckbd\u003eEnter\u003c/kbd\u003e 打开菜单时，将聚焦菜单的首个可聚焦元素，在菜单中持续 \u003ckbd\u003eTab\u003c/kbd\u003e 时，焦点会在首尾可聚焦元素之间循环。\n\n### Group\n\n```javascript\nimport { Group } from \"hanav\";\n```\n\n`\u003cGroup\u003e` 只用于 `\u003cTrigger\u003e` 或后面将介绍的 `\u003cMiniTrigger\u003e` 中，它可以将多个触发器设为一组，方便添加样式。\n\n### 关闭动画与自定义 x/y 轴动画\n\n关闭动画很重要，当用户设置了操作系统的“减弱动态效果”后，浏览器可以检测到这个选项，网站的提供者可以根据这个选项，展示无动画效果版本的 hanav：\n\n```javascript\nimport { ReducedMotionContent } from \"hanav\";\n```\n\n`\u003cReducedMotionContent\u003e` 使用方法和 `\u003cContent\u003e` 一致。\n\nhanav 的 x/y 轴默认动效是滑动，开发者可以根据自己的场景，进行 x/y 轴动效的定制。\n\n定制 x 轴动效：\n\n```javascript\nimport { CustomXMotionContent } from \"hanav\";\n```\n\n定制 y 轴动效：\n\n```javascript\nimport { CustomYMotionContent } from \"hanav\";\n```\n\n定制 x 轴和 y 轴动效：\n\n```javascript\nimport { CustomMotionContent } from \"hanav\";\n```\n\n定制动效组件相比 `\u003cContent\u003e` 额外接受几个属性，分别是 `xTrans`、`yTrans`、`trans`。`\u003cCustomMotionContent\u003e` 使用 `xTrans` 和 `yTrans` 定制 x/y 轴动画，`trans` 可以被 `\u003cCustomXMotionContent\u003e` 和 `\u003cCustomYMotionContent\u003e` 使用定制动画。\n\n- `xTrans`，定制面板切换时的 x 轴过渡动画，传入一个对象，对象的键是 CSS 属性，值是字符串或长度为 2 或 3 的数组，长度 2 的数组表示动画拥有**起止**两个状态，长度 3 的数组表示动画有**进入前**、**正常**、**退出后**三个状态，除了这两种数组类型，还接受一个特殊的 `transition` 属性，用于设置切换动画时的过渡时间，值为 `false` 或字符串，如果不设置将应用默认值，如果设置为 `false` 将不应用默认值；\n- `yTrans`，定制整个面板的收起和展开 y 轴过渡动画，传入一个对象，对象的键是 CSS 属性，值是字符串或长度为 2 的数组，数组值表示动画的**起止**状态，和 `xTrans` 一样，`yTrans` 也接受一个特殊的 `transition` 属性用于设置动画的过渡时间，同样可以设置为 `false` 或字符串；\n- `trans`，当属性在 `\u003cCustomXMotionContent\u003e` 时，用法和 `xTrans` 一致，当属性在 `\u003cCustomYMotionContent\u003e` 中时，用法和 `yTrans` 一致。\n\n下面是一个设置 x 轴动画，`xTrans` 渐变进入、离开的自定义过渡动画例子：\n\n```json\n{\n  \"opacity\": [0, 1],\n  \"transform\": [\"translate(0)\", \"translateX(-280px)\", \"translateX(280px)\"]\n}\n```\n\n### 移动端视图 mini 系列\n\n移动端系列组件包括 `\u003cMiniNavBar\u003e`、`\u003cMiniTrigger\u003e`、`\u003cMiniContent\u003e`、`\u003cMiniItem\u003e`、`\u003cMiniMenu\u003e`、`\u003cMiniToggle\u003e`、`\u003cMiniBack\u003e`。\n\nmini 组件不需要传递任何参数，所以更容易使用。传入的属性，会直接透传到渲染的 dom 元素上。下面是使用 mini 组件的大致形态，完整范例请查看仓库的 [`dark-space` 文件夹](./examples/dark-space/components/header/mini-nav.jsx)：\n\n```javascript\nimport { MiniNavBar, MiniTrigger, MiniItem, MiniContent, MiniMenu, MiniToggle, MiniBack } from \"hanav\";\n\nexport default function MyLittleNav() {\n  return \u003cMiniNavBar\u003e\n    \u003ca\u003eRepo\u003c/a\u003e\n    \u003cMiniToggle /\u003e\n    \u003cMiniMenu\u003e\n      \u003cMiniTrigger\u003e\n        \u003cMiniItem\u003e\u003cbutton\u003ehanav\u003c/button\u003e\u003c/MiniItem\u003e\n        \u003cMiniItem\u003e\u003cbutton\u003epostcss-mobile-forever\u003c/button\u003e\u003c/MiniItem\u003e\n        \u003ca\u003eabout\u003c/a\u003e\n      \u003c/MiniTrigger\u003e\n      \u003cMiniContent\u003e\n        \u003cMiniItem\u003e{(p, head, tail) =\u003e \u003cdiv {...p}\u003e\n          \u003cMiniBack ref={head} /\u003e\n          \u003ca\u003eHome Page\u003c/a\u003e\n          \u003ca ref={tail} href=\"https://github.com/wswmsword/hanav/blob/main/images/wechat-pay.png\"\u003eDonate\u003c/a\u003e\n        \u003c/div\u003e}\u003c/MiniItem\u003e\n        \u003cMiniItem\u003e\u003cdiv\u003e\n          \u003ca\u003eHome Page\u003c/a\u003e\n          \u003cMiniBack\u003eBack To Main Menu\u003c/MiniBack\u003e\n          \u003ca\u003eBye Bye\u003c/a\u003e\n        \u003c/div\u003e\u003c/MiniItem\u003e\n      \u003c/MiniContent\u003e\n    \u003c/MiniMenu\u003e\n  \u003c/MiniNavBar\u003e;\n}\n```\n\nmini 组件的使用方式和非 mini 组件一致，只需要注意新增的 `\u003cMiniToggle\u003e` 和 `\u003cMiniBack\u003e`。\n\n`\u003cMiniToggle\u003e` 一般用来展示汉堡按钮，控制菜单的展开与收起，它的 children 可以是一个 render prop，入参是菜单是否打开的状态。\n\n`\u003cMiniTrigger\u003e` 是一个菜单列表，点击其中一项，会进入详情（对应的 `\u003cMiniContent\u003e` 下的 `\u003cMiniItem\u003e`），而 `\u003cMiniBack\u003e` 就是一个从详情返回至菜单列表（`\u003cMiniTrigger\u003e`）的按钮。\n\n## 键盘交互\n\n| Key | Description |\n|:--|:--|\n| \u003ckbd\u003eTab\u003c/kbd\u003e | 当焦点在触发器上，将从前往后逐个聚焦，当焦点在内容面板中，焦点将在头元素和尾元素之间循环 |\n| \u003ckbd\u003eSpace\u003c/kbd\u003e \u003ckbd\u003eEnter\u003c/kbd\u003e | 当焦点在触发器上，按下按键，会展开或收起内容面板 |\n| \u003ckbd\u003eEsc\u003c/kbd\u003e | 当焦点在内容面板中，按下按键会收起面板，焦点回到触发器 |\n\n## 注意事项\n\nmacOS 里，用户在 Firefox 可能无法使用 \u003ckbd\u003eTab\u003c/kbd\u003e 聚焦链接元素，需要用户执行下面的步骤：打开“系统设置”，打开“键盘”，打开“键盘导航”。\n\n## 开发与维护方向\n\n在项目根目录执行下面的命令，监听组件源码的变化，并实时更新输出：\n\n```bash\nnpm run watch\n```\n\n保持上面的监听命令打开，再打开新的终端会话，执行下面的命令运行引入了源码组件的 React Demo 应用，在更改源码时，在浏览器实时查看效果：\n\n```bash\ncd examples/demo\nnpm i\nnpm run dev\n```\n\n下面的列表是这个项目宏观方向，大概是终端用户、开发者和源码维护三个方面：\n\n- 可访问性\n  - 有正确的 ARIA 标签，能够通过安卓 TalkBack 和 iOS、MacOS 的 VoiceOver 的验证\n  - 能够完全通过键盘控制\n  - 能够切换打开与关闭过渡动画\n  - 响应式设计\n- 流畅的过渡动画\n- 不错的性能\n- 良好的开发体验\n  - 有符合直觉的使用形态\n  - 保留导航栏功能核心，不侵犯开发者的自定义空间\n- 简易的文档\n- 编码整理\n  - 无需遵循特定的格式规范，请自由使用习惯的格式\n  - 编码中的命名合适，在没有找到合适的命名前有详细的注释辅助理解\n  - 上浮和下沉函数，找到合适的抽象层\n\n查看[一些原理](./how-it-works.md)。\n\n## 测试\n\n贡献源码后，首先在[测试文件](./tests/index.spec.js)中添加对应的单元测试，然后运行[仓库的 dark-space 项目](./examples/dark-space)，最后在 hanav 根目录运行测试。\n\n```bash\nnpm run t\n```\n\n## CHANGELOG\n\n查看[更新日志](./CHANGELOG.md)。\n\n## 版本规则\n\n查看[语义化版本 2.0.0](https://semver.org/lang/zh-CN/)。\n\n## 协议\n\n查看 [MIT License](./LICENSE)。\n\n## 支持与赞助\n\n请随意 Issue、PR 和 Star，您也可以支付该项目，支付金额由您从该项目中获得的收益自行决定。\n\n\u003cdetails\u003e\n\u003csummary\u003e展开查看用于微信支付和支付宝支付的二维码。\u003c/summary\u003e\n\n\u003ctable\u003e\n  \u003ctr align=\"center\"\u003e\n    \u003ctd\u003e微信支付\u003c/td\u003e\n    \u003ctd\u003e支付宝支付\u003c/td\u003e\n  \u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e\u003cimg src=\"./images/wechat-pay.png\" alt=\"Pay through WeChat\" /\u003e\u003c/td\u003e\n\t\t\u003ctd\u003e\u003cimg src=\"./images/ali-pay.jpg\" alt=\"Pay through AliPay\" /\u003e\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c/details\u003e\n\n\u003cdiv align=\"right\"\u003e🌷🪻🌹🌻🌷\u003c/div\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwswmsword%2Fhanav","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwswmsword%2Fhanav","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwswmsword%2Fhanav/lists"}