## 1. Project Overview & Quickstart (crimx/CONTRIBUTING-zh)

# CONTRIBUTING-zh

Open-source repository crimx/CONTRIBUTING-zh

### Repository Details
- **Repository:** [crimx/CONTRIBUTING-zh](https://github.com/crimx/CONTRIBUTING-zh)
- **Primary Language:** Code

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (crimx/crimx.github.io)

## File: README.md

# crimx.github.io

> My site

## Build Setup

``` bash
# install dependencies
$ yarn install

# serve with hot reload at localhost:3000
$ yarn run dev

# build for production and launch server
$ yarn run build
$ yarn start

# generate static project
$ yarn run generate
```

For detailed explanation on how things work, checkout [Nuxt.js docs](https://nuxtjs.org).

---

## File: package.json

{
  "name": "crimx.github.io",
  "version": "1.0.0",
  "description": "CRIMX personal site.",
  "author": "CRIMX",
  "private": true,
  "scripts": {
    "dev": "nuxt --hostname 0.0.0.0",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "deploy": "node scripts/deploy.js",
    "ship": "yarn generate && yarn deploy",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "yarn lint"
  },
  "dependencies": {
    "cross-env": "^5.2.0",
    "normalize-scss": "^7.0.1",
    "nuxt": "^2.0.0",
    "nuxt-i18n": "^5.4.4",
    "sass": "^1.41.1"
  },
  "devDependencies": {
    "babel-eslint": "^8.2.1",
    "eslint": "^5.0.1",
    "eslint-config-prettier": "^3.1.0",
    "eslint-loader": "^2.0.0",
    "eslint-plugin-prettier": "2.6.2",
    "eslint-plugin-vue": "^4.0.0",
    "html-loader": "^0.5.5",
    "markdown-loader": "^4.0.0",
    "nodemon": "^1.11.0",
    "prettier": "1.14.3",
    "sass-loader": "^7.1.0",
    "shelljs": "^0.8.3"
  }
}

---

## File: assets/stacks.json

{
  "antd": ["antd", "https://github.com/ant-design/ant-design/", "Ant Design"],
  "bulma": ["bulma", "https://github.com/jgthms/bulma/", "Bulma"],
  "codepen": ["codepen", "https://codepen.io/", "CodePen"],
  "dexie": ["dexie", "https://github.com/dfahlander/Dexie.js", "Dexie(IndexedDB)"],
  "gatsby": ["gatsby", "https://www.gatsbyjs.org/", "Gatsby"],
  "github-api": ["github", "https://developer.github.com/", "Github APIs"],
  "graphql": ["graphql", "https://graphql.org/", "GraphQL"],
  "hexo": ["hexo", "https://hexo.io", "Hexo"],
  "i18next": ["i18next", "https://github.com/i18next/i18next", "I18next"],
  "iview": ["iview", "https://www.iviewui.com/", "IView"],
  "lerna": ["lerna", "https://lerna.js.org/", "Lerna"],
  "netlify": ["netlify", "https://www.netlify.com/", "Netlify"],
  "netlifycms": ["netlifycms", "https://www.netlifycms.org/", "Netlify CMS"],
  "neutrino": ["neutrino", "https://neutrinojs.org", "Neutrino"],
  "nuxt": ["nuxt", "https://github.com/nuxt/nuxt.js", "NUXT"],
  "nuxt-i18n": ["nuxt", "https://github.com/nuxt-community/nuxt-i18n", "Nuxt-i18n"],
  "observable-hooks": ["observable-hooks", "https://github.com/crimx/observable-hooks", "Observable Hooks"],
  "postcss": ["postcss", "https://github.com/postcss/postcss", "PostCSS"],
  "react": ["react", "https://github.com/facebook/react/", "React.js"],
  "redux": ["redux", "https://github.com/reactjs/redux", "Redux"],
  "redux-thunk": ["redux", "https://github.com/reduxjs/redux-thunk", "Redux Thunk"],
  "redux-observable": ["redux-observable", "https://redux-observable.js.org/", "Redux Observable"],
  "rxjs": ["rxjs", "https://github.com/ReactiveX/rxjs", "RxJS"],
  "sass": ["sass", "https://sass-lang.com/", "Sass"],
  "storybook": ["storybook", "https://storybook.js.org/", "Storybook"],
  "typescript": ["typescript", "https://www.typescriptlang.org/", "TypeScript"],
  "vanilla-js": ["javascript", "http: //vanilla-js.com/", "VanillaJS"],
  "vue": ["vue", "https://github.com/vuejs/vue", "Vue.js"],
  "vue-i18n": ["vue", "https://github.com/kazupon/vue-i18n", "Vue-i18n"],
  "vue-router": ["vue", "https://github.com/vuejs/vue-router", "Vue-router"],
  "vue-ssr": ["vue", "https://ssr.vuejs.org/", "Vue SSR"],
  "vuex": ["vue", "https://vuex.vuejs.org/", "Vuex"],
  "webpack": ["webpack", "https://webpack.js.org", "Webpack"]
}

---

## File: projects/blog-2019/en-US.md

A technical blog following [JAMstack architecture](https://jamstack.org/), based on [GatsbyJS](https://gatsbyjs.org), a React Framework using [GraphQL](https://graphql.org/) to manage resources. Post contents are managed on [Netlify CMS](https://www.netlifycms.org/). The whole site is delivered via [Netlify](https://www.netlify.com/) network.

<hr class="read-more" />

This is also an attempt to replace Class components with React Hooks, which brings great convenience and pleasant development experience.

Managing data and resources with GraphQL is also powerful and dead easy.

With Netlify CMS and [Utterances](https://utteranc.es), post files and comments are stored back to Github which reduces the dependency of third-party services.

Site logo are designed with illustrator. Social media icons are taken from [NViconsLib 2](https://github.com/nullice/NViconsLib_Silhouette), edited with [Boxy SVG](https://boxy-svg.com/), merged with [IcoMoon](https://icomoon.io/) and compressed with [SVGOMG](https://jakearchibald.github.io/svgomg/).

---

## File: projects/blog-2019/meta.json

{
  "title": {
    "zh-CN": "CRIMX BLOG",
    "en-US": "CRIMX BLOG"
  },
  "url": "https://blog.crimx.com",
  "stack": [
    "gatsby",
    "graphql",
    "react",
    "bulma",
    "sass",
    "netlifycms",
    "netlify"
  ],
  "badges": {
    "github": "crimx/blog-2019"
  },
  "hideExpand": false
}

---

## File: projects/blog-2019/zh-CN.md

一个基于 [JAMstack](https://jamstack.org/) 架构的技术博客。利用 React 框架 [GatsbyJS](https://gatsbyjs.org) 搭配 [GraphQL](https://graphql.org/) 开发，使用 [Netlify CMS](https://www.netlifycms.org/) 管理文章内容并托管在 [Netlify](https://www.netlify.com/) 平台上。

<hr class="read-more" />

具体更换原因见博文[《为什么选 Gatsby》](https://blog.crimx.com/2019/04/18/%E6%90%AD%E5%BB%BA-gatsby-%E5%8D%9A%E5%AE%A2%E4%B8%80%EF%BC%9A%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89-gatsby/)。

利用 GraphQL 统一管理信息和资源为开发带来了极大的便利。

Netlify CMS 和 [Utterances](https://utteranc.es) 实现了文章和评论数据都保存回 Github 上，减少了第三方服务的依赖。

样式基于一个现代 CSS 框架 [Bulma](https://bulma.io/)， Sass 模块的设计借鉴了 [ITCSS](https://itcss.io/) 思想。

LOGO 图标使用 illustrator 设计，社交图案采用 [NViconsLib 2](https://github.com/nullice/NViconsLib_Silhouette) ，使用 [Boxy SVG](https://boxy-svg.com/) 手工编辑，利用 [IcoMoon](https://icomoon.io/) 合并以及 [SVGOMG](https://jakearchibald.github.io/svgomg/) 压缩。

---

## File: projects/empty-module-loader/en-US.md

A webpack loader that replaces module with empty function which can be eliminated with Webpack [Tree Shaking](https://webpack.js.org/guides/tree-shaking/).

---

## File: projects/empty-module-loader/meta.json

{
  "title": {
    "zh-CN": "Empty Module Loader",
    "en-US": "Empty Module Loader"
  },
  "url": "https://github.com/crimx/empty-module-loader",
  "stack": [
    "webpack"
  ],
  "badges": {
    "npm": "empty-module-loader"
  },
  "hideExpand": true
}

---

## File: projects/empty-module-loader/zh-CN.md

一个可以将特定模块替换为空函数的 webpack loader 。配合 [Tree Shaking ](https://webpack.js.org/guides/tree-shaking/) 可在生成的代码中完全清除。

---

## File: projects/ext-github-release-notifier/en-US.md

Chrome / Firefox extension for watching Github releases.

<hr class="read-more" />

Unofficial "polyfill" for watching Github releases. It was based on [this](https://github.com/isaacs/github/issues/410#issuecomment-291797759) lovely idea. A year later Github finally added basic official [support](https://blog.github.com/changelog/2018-11-27-watch-releases/).

It uses Github APIs and takes advantage of 304 cache.

---

## File: projects/ext-github-release-notifier/meta.json

{
  "title": {
    "zh-CN": "Release Notifier for Github",
    "en-US": "Release Notifier for Github"
  },
  "url": "https://github.com/crimx/ext-github-release-notifier",
  "stack": [
    "vue",
    "github-api"
  ],
  "badges": {
    "github": "crimx/ext-github-release-notifier",
    "chrome": "gjhmlndokehcbkaockjlgeofgkiaiflg",
    "firefox": "release-notifier-for-github"
  },
  "hideExpand": false
}

---

## File: projects/ext-github-release-notifier/zh-CN.md

一款可以按 major、minor 和 patch 版本来订阅 Github release 的 Chrome / Firefox 扩展。

<hr class="read-more" />

灵感源于一个 [issue](https://github.com/isaacs/github/issues/410#issuecomment-291797759) 的讨论。一年后 Github 终于推出了初步的[官方支持](https://blog.github.com/changelog/2018-11-27-watch-releases/)。

请求利用 E-Tags 304 （Not Modified）跳转来快速查询。

---

## File: projects/get-selection-more/en-US.md

Get text and context (sentence, paragraph...) from `window.getSelection()`.

---

## File: projects/get-selection-more/meta.json

{
  "title": {
    "zh-CN": "Get Selection More",
    "en-US": "Get Selection More"
  },
  "url": "https://github.com/crimx/get-selection-more",
  "stack": ["typescript"],
  "badges": {
    "github": "crimx/get-selection-more",
    "npm": "get-selection-more"
  },
  "hideExpand": true
}

---

## File: projects/get-selection-more/zh-CN.md

从 `window.getSelection()` 获取选字以及上下文（所在句子、段落等）。

---

## File: projects/hexo-filter-github-emojis/en-US.md

A Hexo plugin that adds emoji support, using [Github Emojis API](https://api.github.com/emojis).

<hr class="read-more" />

With accessibility in mind, this plugin generates unicodes for emojis then makes the font transparent and displays emoji images with `background-image`.

---

## File: projects/hexo-filter-github-emojis/meta.json

{
  "title": {
    "zh-CN": "Hexo Filter Github Emojis",
    "en-US": "Hexo Filter Github Emojis"
  },
  "url": "https://github.com/crimx/hexo-filter-github-emojis",
  "stack": [
    "hexo",
    "github-api"
  ],
  "badges": {
    "github": "crimx/hexo-filter-github-emojis",
    "npm": "hexo-filter-github-emojis"
  },
  "hideExpand": false
}

---

## File: projects/hexo-filter-github-emojis/zh-CN.md

Hexo 插件，利用 [Github Emojis API](https://api.github.com/emojis) 支持在 Markdown 和 HTML 模板中添加语义化的 emojis 。

<hr class="read-more" />

考虑到可访问性，本插件会生成 emoji 的 unicode 并将字体设为透明，然后在背景图片中添加 Github emoji 图片。当加载失败时恢复字体颜色。

插件同时提供丰富的配置选项，满足各种不同的需求。

---

## File: projects/javascript30/en-US.md

30-day vanilla JS coding challenge. Inspired by Wes Bos's [JavaScript 30](https://javascript30.com/).

<hr class="read-more" />

Some of my interesting ideas:

- [Day 4 Queue*2 = Stack](https://codepen.io/straybugs/pen/YeNKoN): Visualized stack based on two queues.
- [Day 7 Stack*2 = Queue](https://codepen.io/straybugs/pen/QQvKjo): Visualized queue based on two stacks.
- [Day 19 Webcam Fun](https://codepen.io/straybugs/pen/RQYVzm): With canvas transformation.
- [Day 20 Levitation Charm](https://codepen.io/straybugs/pen/MQqLVe): Native Speech Recognition.
- [Day 23 Country Flags Game](https://codepen.io/straybugs/pen/LQMMxq): With Speech Synthesis.
- [Day 27 Jelly Pickle](https://codepen.io/straybugs/pen/yvrdEr): handwritten spring algorithm.
- [Day 29 Digital Clock](https://codepen.io/straybugs/pen/PQrQQY): CSS transform clock. And a updated version - a [counter](https://codepen.io/straybugs/pen/PRGZBa) based on [Recompose](https://github.com/acdlite/recompose) and [RxJS](https://rxjs-dev.firebaseapp.com/).

---

## File: projects/javascript30/meta.json

{
  "title": {
    "zh-CN": "JavaScript 30",
    "en-US": "JavaScript 30"
  },
  "url": "https://codepen.io/collection/DNdQZw/",
  "stack": [
    "codepen",
    "vanilla-js"
  ],
  "badges": {},
  "hideExpand": false
}

---

## File: projects/javascript30/zh-CN.md

三十天每天用纯 JavaScript 、CSS 和 HTML 写个小东西，并尝鲜一些新的浏览器 API 。灵感来自于 Wes Bos 的 [JavaScript 30](https://javascript30.com/) 。他的例子相对简单，我根据自己的能力实现了些更复杂的点子。

<hr class="read-more" />

比较有意思的如

- [Day 4 Queue*2 = Stack](https://codepen.io/straybugs/pen/YeNKoN) 可视化两个队列实现一个栈。
- [Day 7 Stack*2 = Queue](https://codepen.io/straybugs/pen/QQvKjo) 可视化两个栈实现一个队列。
- [Day 19 Webcam Fun](https://codepen.io/straybugs/pen/RQYVzm) 利用 canvas 变换摄像头数据。
- [Day 20 Levitation Charm](https://codepen.io/straybugs/pen/MQqLVe) 麦克风识别悬浮咒。
- [Day 23 Country Flags Game](https://codepen.io/straybugs/pen/LQMMxq) 基于语音合成的猜国旗游戏。
- [Day 27 Jelly Pickle](https://codepen.io/straybugs/pen/yvrdEr) 手写 spring 算法实现 Q 弹腌黄瓜。
- [Day 29 Digital Clock](https://codepen.io/straybugs/pen/PQrQQY) 基于 CSS 变换的时钟，以及升级版基于 [Recompose](https://github.com/acdlite/recompose) 和 [RxJS](https://rxjs-dev.firebaseapp.com/) 的[计时器](https://codepen.io/straybugs/pen/PRGZBa)。

---

## File: projects/leetmark/en-US.md

A Chrome extension that can generate a decent Github Flavored Markdown template from a Leetcode problem page.

Meta data is stored as Front Matter from which Github will generate a neat data table.

---

## File: projects/leetmark/meta.json

{
  "title": {
    "zh-CN": "Leetmark",
    "en-US": "Leetmark"
  },
  "url": "https://github.com/crimx/crx-leetmark",
  "stack": [
    "vanilla-js"
  ],
  "badges": {
    "chrome": "pbpcnaodgahdlijbhjeohbjoafbdafdp"
  },
  "hideExpand": true
}

---

## File: projects/leetmark/zh-CN.md

一款可以将 [Leetcode](https://leetcode.com/problemset/all/) 题目转换为 Markdown 的 Chrome 扩展。题目元数据被保存为 Front Matter 格式。

---

## File: projects/neutrino-webextension/en-US.md

[Neutrino 9](https://neutrinojs.org) preset for WebExtension development with hot reload and framework devtools.

<hr class="read-more" />

Zero upfront configuration necessary to start developing and building a WebExtension.

Run development mode in a fake WebExtension environment which supports hot reload and framework devtools.

Webpack chunks are translated into manifest configs nicely.

Outputs are bundled for each browser respectively, with different manifest.

Works well with other official Neutrino presets.

---

## File: projects/neutrino-webextension/meta.json

{
  "title": {
    "zh-CN": "Neutrino WebExtension",
    "en-US": "Neutrino WebExtension"
  },
  "url": "https://github.com/crimx/neutrino-webextension",
  "stack": ["neutrino", "webpack"],
  "badges": {
    "github": "crimx/neutrino-webextension"
  },
  "hideExpand": false
}

---

## File: projects/neutrino-webextension/zh-CN.md

[Neutrino 9](https://neutrinojs.org) 脚手架插件，开发跨浏览器扩展，支持热更新以及框架 devtools 调试。

<hr class="read-more" />

目前开发浏览器扩展的流程基本还是刀耕火种的方式：

- 引用的 JS 文件和样式文件需要手写到清单文件 `manifest.json` 中，不能享受打包工具的分块优化。
- 各个浏览器的扩展 API 支持不完全一致，`manifest.json` 内容也不完全相同。
- 浏览器对扩展页面访问有限制，故热更新以及框架 devtools 都不能使用。

所以针对这些问题，我设计了一套自动化解决方案，大大简化了开发流程：

- 基于 [Neutrino 9](https://neutrinojs.org) 脚手架开发插件，可以继承其众多优点：开箱即用，可配置性高（[Webpack Chain](https://github.com/neutrinojs/webpack-chain)），有丰富的生态，对各种框架、代码规范都有很好的支持。
- 通过实现一个[扩展环境模拟器](https://github.com/crimx/webextensions-emulator)在普通网页中跑扩展页面，成功支持热更新以及框架 devtools 调试。
- 不再手动配置清单文件，我编写了一个 Webpack 插件自动将打包后的各个块更新到清单相应的配置中。
- 为各个浏览器分别自动打包，自动生成不同的清单配置。

---

## File: projects/observable-hooks/en-US.md

React hooks for RxJS Observables with super flexible APIs.

<hr class="read-more" />

Why:

- Component specific async logic, which are reused with the Component, no longer needs to be delegated to stateful parent or state management libraries.
- With React Hooks, logic can be encapsulated nicely together for easy testing.
- RxJS comes with a mature and abundant ecosystem which can address a wide range of async problems.

Features:

- Simple yer powerful API. Not only easier to use but also simpler to implement and faster to run.
- States, Props and Observables can interconvert into each other seamlessly.
- Observables can be operated directly, whether they are hooks generated or from outside of the Component.
- Operations on Observables are pure just like [Epic](https://redux-observable.js.org/docs/basics/Epics.html) in Redux Observable which can be reused and isolated for testing.
- Supports [Render-as-You-Fetch](https://observable-hooks.js.org/guide/render-as-you-fetch-suspense.html#observable-suspense-hook) pattern with Suspense.
- Fully tested. Stable API.

---

## File: projects/observable-hooks/meta.json

{
  "title": {
    "zh-CN": "Observable Hooks",
    "en-US": "Observable Hooks"
  },
  "url": "https://github.com/crimx/observable-hooks",
  "stack": ["typescript", "react", "rxjs"],
  "badges": {
    "github": "crimx/observable-hooks",
    "npm": "observable-hooks"
  },
  "hideExpand": false
}

---

## File: projects/observable-hooks/zh-CN.md

通过 React hooks 在组件中无缝连接 RxJS Observables 以复用异步逻辑。

<hr class="read-more" />

为什么要在组件中复用异步逻辑：

- 一些只跟当前组件相关的异步逻辑不再需要委托到父组件或者状态管理库，从而达到真正的组件复用。
- React Hooks 紧凑的代码风格可以让逻辑封装到一起，更方便隔离测试。
- 使用 RxJS 是因为其成熟丰富的生态，对简单到复杂的异步逻辑都有很好的解决方案。

相比同类库优势：

- 简洁的 API，不仅更容易使用且实现更简洁，同时提高了性能。
- States 和 Props 可以无缝与 Observables 互相转换。
- 可对多个 Observables 直接进行各种操作，无论是 hooks 中生成的还是组件以外的。
- Observables 的操作是纯净的，类似于 Redux Observable 的 [Epic](https://redux-observable.js.org/docs/basics/Epics.html)，可以复用以及单独进行测试。
- 支持结合 Suspense 实现 [Render-as-You-Fetch](https://observable-hooks.js.org/guide/render-as-you-fetch-suspense.html#observable-suspense-hook) 模式。
- 完善的测试，API 稳定。

---

## File: projects/postcss-safe-important/en-US.md

[PostCSS](https://github.com/postcss/postcss) plugin that adds `!important` to style declarations safely. Used and recommended by many large projects like [Uppy](https://github.com/transloadit/uppy/blob/23f3bf9edcd2248d7d2535a9e29dd48fd70690e7/package.json#L174), [stylelint](https://stylelint.io/user-guide/rules/declaration-no-important/), [vmd](https://github.com/yoshuawuyts/vmd/blob/1f220068c1bf69c02f53bb2c8ac308cba3f8ccfb/package.json#L33) and [HoverCards](https://github.com/kogg/hovercards/blob/34c4aac817bf67cbfcc98baca999bc4a21259b74/package.json#L136).

<hr class="read-more" />

1. Accuracy. Unlike other regex based implementations, this plugin uses AST (Abstract Syntax Tree) generated by PostCSS to accurately locate rules.
2. Safety. Adding `!important` to every declarations might break styles. This plugin will skip unnecessary declarations.
3. Configurability. Flexible and fine-grained control over the plugin.

---

## File: projects/postcss-safe-important/meta.json

{
  "title": {
    "zh-CN": "PostCSS Safe Important",
    "en-US": "PostCSS Safe Important"
  },
  "url": "https://github.com/crimx/postcss-safe-important",
  "stack": [
  	"postcss"
  ],
  "badges": {
    "github": "crimx/postcss-safe-important",
    "npm": "postcss-safe-important"
  },
  "hideExpand": false
}

---

## File: projects/postcss-safe-important/zh-CN.md

[Binary file]

---

## File: projects/projects/en-US.md

NUXT based static website.

<hr class="read-more" />

With SSR generated static pages, DOM can be rendered before JavaScript loading, after which Vue will take over DOM manipulation and routing is controled by Vue-router.

为项目介绍抽象出共用部分，实现组件复用，每个项目介绍只需简单配置即可添加。

Common parts of each project description are abstracted and resued. Adding a new project description can be achieved with minimum configuration.

Nuxt-i18n overrides Nuxt default routes and adds locale prefixes to every URL. Description of each project is written in Markdown and transformed to HTML via [markdown-loader](https://github.com/peerigon/markdown-loader).

---

## File: projects/projects/meta.json

{
  "title": {
    "zh-CN": "本项目",
    "en-US": "This Project"
  },
  "url": "https://github.com/crimx/crimx.github.io",
  "stack": [
    "nuxt",
    "nuxt-i18n",
    "vue"
  ],
  "badges": {},
  "hideExpand": false
}

---

## File: projects/projects/zh-CN.md

基于 NUXT 生成的静态网站。

<hr class="read-more" />

利用 SSR （服务器渲染）为每个路由生成了静态页面，故打开页面无需加载 JavaScript 即可开始渲染 DOM ，待 JavaScript 加载完成后由 Vue 接管 DOM 以及 Vue-router 接管路由跳转。

为项目介绍抽象出共用部分，实现组件复用，每个项目介绍只需简单配置即可添加。

使用了 nuxt-i18n 自动生成多语言路由，动态加载，每个项目的富文本介绍用 Markdown 编写，使用 [markdown-loader](https://github.com/peerigon/markdown-loader) 转换为 HTML 加载。

---

## File: projects/react-resize-reporter/en-US.md

Lightweight React Component that reports width and height changes when its parent resizes.

<hr class="read-more" />

Why:

1. Currently there is no perfect solution for detecting element resizing.
1. Existing solutions are either buggy or with verbose API.

Highlights:

1. Clean API.
1. Two implementations with same interface.

---

## File: projects/react-resize-reporter/meta.json

{
  "title": {
    "zh-CN": "React Resize Reporter",
    "en-US": "React Resize Reporter"
  },
  "url": "https://github.com/crimx/react-resize-reporter",
  "stack": ["typescript", "react"],
  "badges": {
    "github": "crimx/react-resize-reporter",
    "npm": "react-resize-reporter"
  },
  "hideExpand": false
}

---

## File: projects/react-resize-reporter/zh-CN.md

监听 React 组件尺寸变化。

<hr class="read-more" />

为什么：

1. 目前没有完美的解决方案监听 React 组件尺寸变化。
1. 现有的解决方案要么不稳定要么使用非常啰嗦的 API。

亮点：

1. 简洁的 API。
1. 两种实现方式，共用一套相同的接口。

---

## File: projects/retux/en-US.md

Minimalist declarative type-safe(strongly-typed) scalable TypeScript Redux architecture.

<hr class="read-more" />

## Features

- Minimalist. Leveraging advanced features of TypeScript Retux reduces boilerplate code with better type-inferring and auto-completion.
- Declarative. Action-First instead of Action-Creator-Fisrt desgin results in code that is clean and easy to read for new contributors and future-self.
- Type-safe(strongly-typed). Retux enforces strict typings. With the utilities in Retux you will never lose the strictness of typings while enjoying great flexibility.
- Scalable. A Retux module can be easily split into isomorphic sub-modules. Retux can also optionally leverage the power of meta-programming on modern engine for further performance boost.

---

## File: projects/retux/meta.json

{
  "title": {
    "zh-CN": "Retux",
    "en-US": "Retux"
  },
  "url": "https://github.com/crimx/retux",
  "stack": ["typescript", "redux", "lerna"],
  "badges": {
    "github": "crimx/retux"
  },
  "hideExpand": false
}

---

## File: projects/retux/zh-CN.md

简洁、声明式、类型安全（强类型）、可扩展的 TypeScript Redux 架构。

<hr class="read-more" />

## 特性

- 简洁。借助 TypeScript 的高级特性 Retux 在减少样板代码的同时保持更好的类型推导和自动补全。
- 声明式。Action 优先而不是 Action Creator 优先的设计使到代码更加清晰易懂，特别是对项目新成员还有未来的自己。
- 类型安全（强类型）。Retux 使用严格的类型。通过 Retux 的工具可以灵活地编写 TypeScript 代码而不会失去类型的严格性。
- 可扩展。Retux 模块可以轻易划分为多个同构的子模块。Retux 同时可以在现代引擎上借助元编程进一步提升性能。

---

## File: projects/saladict/en-US.md

A handy dictionary extension with eye-pleasing UI. Praised([Chrome review](https://chrome.google.com/webstore/detail/cdonnmffkdaoajfknoeeecmchibpmkmg?hl=en) / [Firefox review](https://addons.mozilla.org/zh-CN/firefox/addon/ext-saladict/reviews/)) and supported by hundreds of thousands of users.

<hr class="read-more" />

Highlights in terms of functional design:

1. Results from different dictionaries are integrated into one panel with consistent styles for easy cross-reference.
1. Rapid searching with multiple search modes plus different profiles.
1. Search text contexts as well as translations are kept in notebook.
1. High accessibility. Inside iframes, PDFs and even outside of browser.
1. Follow Unix philosophy. Focus on experience on looking up words while offering flexible interface for force multiplier effects [with other tools](https://saladict.crimx.com/en/manual.html#shortcuts).

Highlights in terms of technical implementation:

1. Mass use of [React Hooks](https://reactjs.org/docs/hooks-intro.html) for abstracting Component async UI logic, with [RxJS](https://github.com/ReactiveX/rxjs) handling complex user inputs(See my other project [observable-hooks](https://github.com/crimx/observable-hooks)).
1. Components are built with [Storybook](https://storybook.js.org) which enables rapid UI development.
1. Syltes of dictionary panel and each dictionary are isolated with [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) with lower cost of performance.
1. Automation are introduced into the build process(with my other project [neutrino-webextension](https://github.com/crimx/neutrino-webextension)). Dictionaries are loaded with a plugin mechanism.

---

## File: projects/saladict/meta.json

{
  "title": {
    "zh-CN": "Saladict 沙拉查词",
    "en-US": "Saladict"
  },
  "url": "https://saladict.crimx.com/",
  "stack": [
    "typescript",
    "react",
    "observable-hooks",
    "redux",
    "redux-observable",
    "redux-thunk",
    "rxjs",
    "dexie",
    "i18next",
    "antd",
    "sass",
    "neutrino",
    "storybook"
  ],
  "badges": {
    "github": "crimx/ext-saladict",
    "chrome": "cdonnmffkdaoajfknoeeecmchibpmkmg",
    "firefox": "ext-saladict"
  },
  "hideExpand": false
}

---

## File: projects/saladict/zh-CN.md

专业划词扩展，其新颖的设计与实现得到大量用户的肯定与喜爱。许多用户留言评价（[谷歌留言](https://chrome.google.com/webstore/detail/cdonnmffkdaoajfknoeeecmchibpmkmg?hl=en) / [火狐留言](https://addons.mozilla.org/zh-CN/firefox/addon/ext-saladict/reviews/)）这是其用过最好用的划词扩展。

<hr class="read-more" />

功能设计的亮点，

1. 聚合多个词典的结果可以取各所长，并用统一的风格重排显示，极大地方便了交叉查阅词典。
1. 多重划词模式再结合多种情景模式能让用户快速切换，以不同方式灵活查词。
1. 生词本保留了查词的上下文并自动获取整句翻译，以保证准确理解、记忆单词。
1. 高可访问性，兼容各种复杂不一的网页，兼容 iframe 内划词，支持 PDF 划词。
1. Unix 哲学，专注查词并提供灵活的接口，[配合其它工具](https://saladict.crimx.com/manual.html#shortcuts)发挥更强大的功能。

技术实现的亮点，

1. 大量使用 [React Hooks](https://reactjs.org/docs/hooks-intro.html) 为组件复用异步交互逻辑，利用 [RxJS](https://github.com/ReactiveX/rxjs) 处理复杂的用户输入，同时为此开发出另一项目 [observable-hooks](https://github.com/crimx/observable-hooks)。
1. 使用 [Storybook](https://storybook.js.org) 开发组件，在可视化环境中快速调试。
1. 在 React 上使用 [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) 以较低成本隔离词典面板以及各个词典的样式。
1. 整合词典结果需要理解不同词典网页的设计，并从中总结出规律，稳定地为用户提炼展现有用的信息。
1. 自动化构建脚本，为此开发出专用脚手架插件 [neutrino-webextension](https://github.com/crimx/neutrino-webextension)。代码结构多层抽象，添加词典采用插件式机制载入。

---

## File: projects/side-effect-manager/en-US.md

A tiny library to encapsulate side effects in a compact, reusable and testable style.

---

## File: projects/side-effect-manager/meta.json

{
  "title": {
    "zh-CN": "Side Effect Manager",
    "en-US": "Side Effect Manager"
  },
  "url": "https://github.com/crimx/side-effect-manager",
  "stack": ["typescript"],
  "badges": {
    "github": "crimx/side-effect-manager",
    "npm": "side-effect-manager"
  },
  "hideExpand": true
}

---

## File: projects/side-effect-manager/zh-CN.md

一个超小的库用于以紧凑、可复用、可测试的方式编写副作用代码。

---

## File: projects/use-suspensible/en-US.md

React hooks that can make any data suspensible.

<hr class="read-more" />

Why:

If you follow the Relay Suspense pattern you need to [add wrappers to async logic](https://github.com/relayjs/relay-examples/blob/205dfb195c770e7cd3977116654bd69c91d03b90/issue-tracker/src/JSResource.js#L21-L42) then use [read()](https://github.com/relayjs/relay-examples/blob/master/issue-tracker/src/JSResource.js#L54-L717) to [get data in Components](https://github.com/relayjs/relay-examples/blob/205dfb195c770e7cd3977116654bd69c91d03b90/issue-tracker/src/SuspenseImage.js#L27).

This means:

- It can only apply to Promise based async logic.
- You have to write logic and use data in a specific way.
- When you successfully `read()` a piece of data, it means the data is "fetched" but not necessary "usable"(unless you write business logic in a conventional way to make sure they are the same). You still need to add logic to check e.g. variation/validation of the data.

[use-suspensible](https://github.com/crimx/use-suspensible) does not care how you implement the business logic. It only cares about if the data is usable or not. This makes it a universal solution for Suspense.

With [use-suspensible](https://github.com/crimx/use-suspensible) you simply fetch and use data as usual/you like. It just works (with almost no cost).

---

## File: projects/use-suspensible/meta.json

{
  "title": {
    "zh-CN": "Use Suspensible",
    "en-US": "Use Suspensible"
  },
  "url": "https://github.com/crimx/use-suspensible",
  "stack": ["typescript", "react"],
  "badges": {
    "github": "crimx/use-suspensible",
    "npm": "use-suspensible"
  },
  "hideExpand": false
}

---

## File: projects/use-suspensible/zh-CN.md

可以让任何数据触发 Suspense 的 React hooks。

<hr class="read-more" />

为什么：

如果使用 Relay Suspense 方式进行开发的话需要[对异步逻辑进行包装](https://github.com/relayjs/relay-examples/blob/205dfb195c770e7cd3977116654bd69c91d03b90/issue-tracker/src/JSResource.js#L21-L42)然后在组件中使用 [read()](https://github.com/relayjs/relay-examples/blob/master/issue-tracker/src/JSResource.js#L54-L717) 来[获取数据](https://github.com/relayjs/relay-examples/blob/205dfb195c770e7cd3977116654bd69c91d03b90/issue-tracker/src/SuspenseImage.js#L27)。

这意味着：

- 这种方式只能应用到基于 Promise 的异步逻辑。
- 逻辑编写和数据使用需要按照特定的方式。
- 当从`read()`成功获得数据，这仅代表数据“成功返回”而不一定这个数据是“可用的”（除非在逻辑编写上做相应的规范要求两者一致）。所以获得数据后依然还要做各种判断验证数据。

[use-suspensible](https://github.com/crimx/use-suspensible) 不在乎异步逻辑是怎么实现的，它只关心这个数据是否可用，不可用便触发 Suspense。这使到它是一种通用的 Suspense 解决方案。

使用 [use-suspensible](https://github.com/crimx/use-suspensible) 只需要按习惯的方式获取和使用数据即可，逻辑编写不需要做任何改变。

---

## File: projects/value-enhancer/en-US.md

A tiny library to enhance value with reactive wrapper.

---

## File: projects/value-enhancer/meta.json

{
  "title": {
    "zh-CN": "Value Enhancer",
    "en-US": "Value Enhancer"
  },
  "url": "https://github.com/crimx/value-enhancer",
  "stack": ["typescript"],
  "badges": {
    "github": "crimx/value-enhancer",
    "npm": "value-enhancer"
  },
  "hideExpand": true
}

---

## File: projects/value-enhancer/zh-CN.md

一个超小的库用于响应式编程。

---

## File: projects/webextension-store-meta/en-US.md

Get browser extension(webextension) item meta from Chrome Web Store and Firefox add-ons. Used by [Shields.io](https://shields.io/) and [Badgen](https://badgen.net/chrome-web-store).

---

## File: projects/webextension-store-meta/meta.json

{
  "title": {
    "zh-CN": "Webextension Store Meta",
    "en-US": "Webextension Store Meta"
  },
  "url": "https://github.com/crimx/webextension-store-meta",
  "stack": ["vanilla-js"],
  "badges": {
    "github": "crimx/webextension-store-meta",
    "npm": "webextension-store-meta"
  },
  "hideExpand": true
}

---

## File: projects/webextension-store-meta/zh-CN.md

获取浏览器扩展元数据，使用轻量、稳定、高效的方式。已被著名的开源徽章库 [Shields.io](https://shields.io/) 和 [Badgen](https://badgen.net/chrome-web-store) 采用。

---

## File: projects/webpack-target-webextension/en-US.md

WebExtension Target for Webpack 4. Supports code-splitting with native dynamic import.

<hr class="read-more" />

Dynamically loading chunks is not possible in WebExtension content scripts with the default Webpack JSONP.

This library is also included in the [neutrino-webextension preset](https://github.com/crimx/neutrino-webextension).

---

## File: projects/webpack-target-webextension/meta.json

{
  "title": {
    "zh-CN": "Webpack Target WebExtension",
    "en-US": "Webpack Target WebExtension"
  },
  "url": "https://github.com/crimx/webpack-target-webextension",
  "stack": ["webpack"],
  "badges": {
    "github": "crimx/webpack-target-webextension",
    "npm": "webpack-target-webextension"
  },
  "hideExpand": false
}

---

## File: projects/webpack-target-webextension/zh-CN.md

适用于 Webpack 4 的 WebExtension Target 。利用原生 import 动态加载分块。

<hr class="read-more" />

Webpack 默认的 JSONP 机制无法在 WebExtension 的 content scripts 中动态加载分块。

相关原理见我的文章[「自定义 Webpack Target」](https://blog.crimx.com/2020/03/29/%E8%87%AA%E5%AE%9A%E4%B9%89-webpack-target/)。

这个库已经内置到 [neutrino-webextension preset](https://github.com/crimx/neutrino-webextension) 中。

---

## File: projects/weitweet/en-US.md

Chrome / Firefox extension. Share Fanfou, Twitter and Weibo in one click.

<hr class="read-more" />

1. Abstract OAuth 1a & 2 flows using template design pattern to support different platforms（OAuth 1a with Fanfou and Twitter, Oauth 2 with Weibo）.
2. Serverless OAuth flow with `chrome.identity` and content script magic.
3. UI with [iview](https://iviewui.com).
4. Build system is vue-cli based and extended with webpack-chain, which enables building and packing in one click.

---

## File: projects/weitweet/meta.json

{
  "title": {
    "zh-CN": "小推 WeiTweet",
    "en-US": "WeiTweet"
  },
  "url": "https://github.com/crimx/crx-weitweet",
  "stack": [
    "typescript",
    "vue",
    "iview",
    "sass"
  ],
  "badges": {
    "github": "crimx/crx-weitweet",
    "chrome": "jcgjbjbbcjgkpdanbnafdbdlbjacdkln",
    "firefox": "weitweet"
  },
  "hideExpand": false
}

---

## File: projects/weitweet/zh-CN.md

一款可以分享网页到饭否、推特和微博的 Chrome / Firefox 扩展。并可以从网页中提取所有图片。

<hr class="read-more" />

1. 对 OAuth 1a 与 2 的验证流程消化理解，并抽象出通用类利用模板模式支持各个平台（饭否与推特使用 OAuth 1a，微博使用 Oauth 2）。
2. 利用 `chrome.identity` 以及 content script 黑科技实现 OAuth 的无服务器自动授权。
3. UI 完全基于 [iview](https://iviewui.com) 。
4. 代码构建系统利用 webpack-chain 基于 vue-cli 展开，一键构建打包。

---

## File: static/ads.txt

google.com, pub-6993077405597797, DIRECT, f08c47fec0942fa0