Full Code of brucx/wepy-zanui-demo for AI

v2.4.4 9a7d5e5d1a16 cached
60 files
121.1 KB
39.9k tokens
1 requests
Download .txt
Repository: brucx/wepy-zanui-demo
Branch: v2.4.4
Commit: 9a7d5e5d1a16
Files: 60
Total size: 121.1 KB

Directory structure:
gitextract_deywg9a2/

├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── src/
│   ├── app.wpy
│   ├── components/
│   │   ├── zan-actionsheet.wpy
│   │   ├── zan-capsule.wpy
│   │   ├── zan-dialog.wpy
│   │   ├── zan-field.wpy
│   │   ├── zan-loadmore.wpy
│   │   ├── zan-noticebar.wpy
│   │   ├── zan-popup.wpy
│   │   ├── zan-select.wpy
│   │   ├── zan-stepper.wpy
│   │   ├── zan-steps.wpy
│   │   ├── zan-switch.wpy
│   │   ├── zan-tab.wpy
│   │   ├── zan-toast.wpy
│   │   └── zan-toptips.wpy
│   ├── example/
│   │   ├── actionsheet.wpy
│   │   ├── badge.wpy
│   │   ├── btn.wpy
│   │   ├── capsule.wpy
│   │   ├── card.wpy
│   │   ├── cell.wpy
│   │   ├── dashboard.wpy
│   │   ├── dialog.wpy
│   │   ├── field.wpy
│   │   ├── helper.wpy
│   │   ├── icon.wpy
│   │   ├── label.wpy
│   │   ├── layout.wpy
│   │   ├── loadmore.wpy
│   │   ├── noticebar.wpy
│   │   ├── panel.wpy
│   │   ├── popup.wpy
│   │   ├── select.wpy
│   │   ├── stepper.wpy
│   │   ├── steps.wpy
│   │   ├── switch.wpy
│   │   ├── tab.wpy
│   │   ├── tag.wpy
│   │   ├── toast.wpy
│   │   └── toptips.wpy
│   └── zanui/
│       ├── badge.scss
│       ├── btn.scss
│       ├── card.scss
│       ├── cell.scss
│       ├── col.scss
│       ├── color.scss
│       ├── common.scss
│       ├── helper.scss
│       ├── icon.scss
│       ├── panel.scss
│       ├── row.scss
│       └── tag.scss
└── wepy.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true


================================================
FILE: .eslintignore
================================================
dist/*


================================================
FILE: .eslintrc.js
================================================
module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  env: {
    browser: true
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
  extends: 'standard',
  // required to lint *.wpy files
  plugins: [
    'html'
  ],
  settings: {
    'html/html-extensions': ['.html', '.wpy']
  },
  'globals': {
      'wx': true
  },
  // add your custom rules here
  'rules': {
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    "semi": [
        "error",
        "never"
    ],
    'comma-dangle': ["error", "only-multiline"],
    'padded-blocks': 0,
    'one-var': 0,
    'no-return-assign': 0,
    'indent': ['error', 2],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'space-before-function-paren': 0
  }
}


================================================
FILE: .gitignore
================================================
dist/
node_modules/
web/style
sftp-config.json
log
npm-debug.log
.vscode
coverage
lerna-debug.log
.DS_Store
.wepycache


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2016 wepyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# ZanUI in WePY

[ZanUI](https://github.com/youzan/zanui-weapp) 有赞移动 Web UI 规范 ZanUI 的小程序现实版本,结合了微信的视觉规范,为用户提供更加统一的使用感受。

这里是 ZanUI 在 WePY 中的移植。

## 体验步骤

### 1. 安装 wepy
本项目基于wepy开发,[参考这里](https://github.com/wepyjs/wepy)
```bash
yarn global add wepy-cli
```

### 2. 下载源代码
```bash
git clone https://github.com/brucx/wepy-zanui-demo.git
```

### 3. 安装开发依赖
```bash
cd wepy-zanui-demo
yarn
```

### 4. 编译源代码
```bash
wepy build
```

### 5.导入至开发者工具

编译完成后会生成`dist`目录,开发者工具本地开发目录指向`dist`目录。

**切记: 取消勾选`项目-->开启ES6转ES5`,否则代码运行报错。**

# ZanUI-Wepy 组件的使用说明

目前 ZanUI-Wepy 一共有23个组件,分为纯样式组件、封装样式组件、内部交互组件、外部交互组件。具体组件接口可以参考 `example` 目录下的示例。

## 纯样式组件

纯样式组件只需引入相应的 .SCSS 样式文件,然后在项目中引用相应的样式类即可。

包含的组件有:Badge、Button、Card、Cell、Helper、Icon、Layout、Panel、Tag

以"Badge 徽章"为例:

复制 `zanui/badge.scss` 文件至项目目录

页面中如下方式使用

```Vue
<style lang="css">
@import '/zanui/badge.wxss';
</style>

<template>
<view class="zan-badge">
  <view class="zan-badge__count">99+</view>
</view>
</template>
```

## 封装样式组件

封装样式组件需要引入 .WPY 组件文件,通过 Props 传入参数即可。

包含的组件有:Capsule、Loadmore、Steps

以"Capsule 胶囊"为例:

复制 `components/zan-capsule.wpy` 文件至项目目录

页面中如下方式使用

```Vue
<template>
  <zanCapsule :options="zanCapsule" />
</template>

<script>
import wepy from 'wepy'
import zanCapsule from '../components/zan-capsule'

export default class Capsule extends wepy.page {
  components = {
    zanCapsule
  }
  data = {
    zanCapsule: {
      type: 'danger',
      leftText: '2折',
      rightText: '限购两份'
    }
  }
}
</script>
```

## 内部交互组件

内部交互组件需要引入 .WPY 组件文件,通过 Props 传入参数,组件通过事件向页面通信。

包含的组件有:Select、Stepper、Switch、Tab

以"Tab 标签"为例:

复制 `components/zan-tab.wpy` 文件至项目目录

页面中如下方式使用

```Vue
<template>
  <zanTab :options="tab" componentId="tab" />
</template>

<script>
import wepy from 'wepy'
import zanTab from '../components/zan-tab'

export default class Capsule extends wepy.page {
  components = {
    zanTab
  }
  data = {
    tab: {
      list: [
        {
          id: 'all',
          title: '全部'
        },
        {
          id: 'topay',
          title: '待付款'
        },
        {
          id: 'tosend',
          title: '待发货'
        },
        {
          id: 'send',
          title: '待收货'
        },
        {
          id: 'sign',
          title: '已完成'
        }
      ],
      selectedId: 'all',
      scroll: false
    }
  }
  events = {
    zanTabChange({ selectedId }, event) {
      let { componentId } = event.source
      console.log('Page Tab receive selectedId:', componentId, selectedId)
      // 此处进行业务逻辑处理...
    }
  }
</script>
```

## 外部交互组件

外部交互组件需要引入 .WPY 组件文件,通过 Props 传入参数,页面可以主动调用组件方法,组件通过事件向页面通信。

包含的组件有:Actionsheet、Dialog、Field、Noticebar、Popup、Toast、Toptips

以"Actionsheet 行动按钮"为例:

复制 `components/zan-actionsheet.wpy` 文件至项目目录

页面中如下方式使用

```Vue
<template>
  <button @tap="toggleActionsheet">
    Actionsheet
  </button>
  <zanTab :options="tab" componentId="tab" />
</template>

<script>
import wepy from 'wepy'
import zanActionsheet from '../components/zan-actionsheet'

export default class Capsule extends wepy.page {
  components = {
    zanActionsheet
  }
  methods = {
    toggleActionsheet() {
      this.$invoke('zanActionsheet', 'showZanActionsheet', {
        cancelText: '关闭 Action',
        closeOnClickOverlay: true,
        actions: [
          {
            type: 'first',
            name: '选项1',
            subname: '选项描述语1',
            className: 'action-class',
            asyncJob: function() {
              return new Promise((resolve, reject) => {
                setTimeout(() => {
                  resolve()
                }, 1500)
              }) // 可以接受一个异步任务作为参数
            }
          },
          {
            type: 'second',
            name: '选项2',
            subname: '选项描述语2',
            className: 'action-class',
          },
          {
            type: 'share',
            name: '去分享',
            openType: 'share'
          }
        ]
      })
        .then(result => {
          console.log(result.type)  // result.type 为点击选项的 type
        })
        .catch(e => {
          console.log('行动取消')
        })
    }
  }
</script>
```


================================================
FILE: package.json
================================================
{
  "name": "wepy-wechat-demo",
  "version": "2.4.4",
  "description": "基于有赞zanui-weapp的wepy组件库",
  "main": "dist/app.js",
  "scripts": {
    "build": "cross-env NODE_ENV=production wepy build --no-cache",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Bruce Xiong",
  "license": "ISC",
  "dependencies": {
    "wepy": "^1.6.0",
    "wepy-async-function": "^1.4.4",
    "wepy-com-toast": "^1.0.3"
  },
  "devDependencies": {
    "babel-eslint": "^7.2.1",
    "babel-plugin-syntax-export-extensions": "^6.13.0",
    "babel-plugin-transform-export-extensions": "^6.22.0",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-stage-1": "^6.22.0",
    "cross-env": "^3.2.4",
    "eslint": "^3.18.0",
    "eslint-config-standard": "^7.1.0",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-plugin-html": "^2.0.1",
    "eslint-plugin-promise": "^2.0.1",
    "eslint-plugin-standard": "^2.0.1",
    "wepy-compiler-babel": "^1.5.1",
    "wepy-compiler-less": "^1.3.10",
    "wepy-compiler-sass": "0.0.3",
    "wepy-eslint": "^1.5.3",
    "wepy-plugin-imagemin": "^1.5.2",
    "wepy-plugin-uglifyjs": "^1.3.6"
  }
}


================================================
FILE: src/app.wpy
================================================
<style lang="css">
@import '/zanui/helper.wxss';

.container {
  background: #f9f9f9;
  overflow: hidden;
  min-height: 100vh;
  box-sizing: border-box;
  padding: 15px 0;
}
.container::before {
  position: fixed;
  top: 0;
  left: 0;
  content: ' ';
  width: 100%;
  height: 1rpx;
  background-color: #e2e2e2;
  z-index: 5;
}
.doc-title {
  position: relative;
  padding: 15px 0;
  margin: 10px 15px;
  line-height: 25px;
  font-size: 25px;
  color: #666;
}
.doc-description {
  margin: 14px 0;
  padding: 0 15px;
  font-size: 14px;
  line-height: 20px;
  color: #666;
}
</style>

<script>
import wepy from 'wepy'
import 'wepy-async-function'

export default class extends wepy.app {
  config = {
    pages: [
      'example/dashboard',
      'example/actionsheet',
      'example/btn',
      'example/badge',
      'example/capsule',
      'example/card',
      'example/cell',
      'example/dialog',
      'example/field',
      'example/helper',
      'example/icon',
      'example/layout',
      'example/loadmore',
      'example/noticebar',
      'example/panel',
      'example/popup',
      'example/select',
      'example/stepper',
      'example/steps',
      'example/switch',
      'example/tab',
      'example/tag',
      'example/toptips',
      'example/toast'
    ],
    window: {
      navigationBarBackgroundColor: '#FAFAFA',
      navigationBarTitleText: 'ZanUI-Wepy',
      navigationBarTextStyle: 'black',
      backgroundTextStyle: 'dark',
      backgroundColor: '#f9f9f9'
    },
    debug: true
  }

  constructor() {
    super()
    this.use('promisify')
  }
}
</script>


================================================
FILE: src/components/zan-actionsheet.wpy
================================================
<style lang="scss">
@import '../zanui/btn.scss';
@import '../zanui/common';

.zan-actionsheet {
  background-color: #f8f8f8;
}

.zan-actionsheet__mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  background: rgba(0, 0, 0, 0.7);
  display: none;
}

.zan-actionsheet__container {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: $background-color;
  transform: translate3d(0, 50%, 0);
  transform-origin: center;
  transition: all 0.2s ease;
  z-index: 11;
  opacity: 0;
  visibility: hidden;
}

.zan-actionsheet__btn.zan-btn {
  height: 50px;
  line-height: 50px;
  margin-bottom: 0;

  &::after {
    border-width: 0;
    border-bottom-width: 1px;
  }
}

.zan-actionsheet__btn.zan-btn:last-child {
  &::after {
    border-bottom-width: 0;
  }
}

.zan-actionsheet__subname {
  margin-left: 2px;
  font-size: 12px;
  color: $gray-darker;
}

.zan-actionsheet__footer {
  margin-top: 10px;
}

/* btn-loading 状态 */
.zan-actionsheet__btn.zan-btn--loading .zan-actionsheet__subname {
  color: transparent;
}

/* zan-actionsheet 展示出来的样式 */
.zan-actionsheet--show .zan-actionsheet__container {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  visibility: visible;
}
.zan-actionsheet--show .zan-actionsheet__mask {
  display: block;
}
</style>
<template>
  <view class="zan-actionsheet {{ zanActionsheet.show ? 'zan-actionsheet--show' : '' }}">
    <view
      class="zan-actionsheet__mask"
      catchtap="handleZanActionsheetMaskClick"
      data-close-on-click-overlay="{{ zanActionsheet.closeOnClickOverlay }}"
      data-component-id="{{ componentId }}"></view>
    <view class="zan-actionsheet__container">
      <!-- 实际按钮显示 -->
      <button
        wx:for="{{ zanActionsheet.actions }}"
        wx:for-index="index"
        wx:for-item="item"
        wx:key="{{ index }}-{{ item.name }}"
        catchtap="handleZanActionsheetBtnClick"
        data-component-id="{{ componentId }}"
        data-index="{{ index }}"
        data-type="{{ item.type }}"
        open-type="{{ item.openType }}"
        class="zan-btn zan-actionsheet__btn {{ item.loading ? 'zan-btn--loading' : '' }} {{ item.className }}"
      >
        <text>{{ item.name }}</text>
        <text
          wx:if="{{ item.subname }}"
          class="zan-actionsheet__subname">{{ item.subname }}</text>
      </button>

      <!-- 关闭按钮 -->
      <view
        wx:if="{{ zanActionsheet.cancelText }}"
        class="zan-actionsheet__footer"
      >
        <button
          class="zan-btn zan-actionsheet__btn"
          catchtap="handleZanActionsheetCancelBtnClick"
          data-component-id="{{ componentId }}"
        >{{ zanActionsheet.cancelText }}</button>
      </view>
    </view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanActionsheet extends wepy.component {
  props = {
    componentId: String
  }
  data = {
    zanActionsheet: {}
  }
  methods = {
    showZanActionsheet(options = {}, e) {
      const {
        cancelText = '关闭 Action',
        closeOnClickOverlay = true,
        actions = [
          {
            type: '1',
            name: '选项1',
            subname: '选项描述语1',
            className: 'action-class',
            loading: false
          },
          {
            type: '2',
            name: '选项2',
            subname: '选项描述语2',
            className: 'action-class',
            loading: false
          },
          {
            type: 'share',
            name: '去分享',
            openType: 'share'
          }
        ]
      } = options
      return new Promise((resolve, reject) => {
        this.zanActionsheet = {
          show: true,
          cancelText,
          closeOnClickOverlay,
          actions,
          // 回调钩子
          resolve,
          reject
        }
        this.$apply()
      })
    },
    resolveCancelClick() {
      const zanActionsheetData = this.zanActionsheet || {}
      const { reject } = zanActionsheetData

      console.info('[zan:actionsheet:cancel]')
      this.zanActionsheet.show = false
      this.$apply()
      reject({
        type: 'cancel'
      })
    },
    handleZanActionsheetMaskClick({ currentTarget = {} }) {
      const dataset = currentTarget.dataset || {}
      const { closeOnClickOverlay } = dataset

      // 判断是否在点击背景时需要关闭弹层
      if (!closeOnClickOverlay) {
        return
      }

      this.methods.resolveCancelClick.call(this)
    },

    handleZanActionsheetCancelBtnClick(e) {
      this.methods.resolveCancelClick.call(this)
    },

    handleZanActionsheetBtnClick({ currentTarget = {} }) {
      const zanActionsheetData = this.zanActionsheet || {}
      const { resolve } = zanActionsheetData
      const dataset = currentTarget.dataset || {}
      const { index, type } = dataset
      const action = this.zanActionsheet.actions[index]

      console.log(`item index ${index} clicked`)

      // 如果是分享按钮被点击, 不处理关闭
      if (type === 'share') {
        return
      }

      if (action.asyncJob) {
        action.loading = true
        this.$apply()

        action
          .asyncJob()
          .then(e => {
            this.zanActionsheet.show = false
            action.loding = false
            this.$apply()
            resolve({
              type
            })
          })
          .catch(e => {
            action.loding = false
            this.$apply()
          })
      } else {
        this.zanActionsheet.show = false
        action.loding = false
        this.$apply()
        resolve({
          type
        })
      }
    }
  }
  computed = {}
}
</script>


================================================
FILE: src/components/zan-capsule.wpy
================================================
<style lang="scss">
.zan-capsule {
  display: inline-block;
  font-size: 12px;
  vertical-align: middle;
  line-height: 19px;
  transform: scale(0.83);
}
.zan-capsule__left,
.zan-capsule__right {
  display: inline-block;
  line-height: 17px;
  height: 19px;
  vertical-align: middle;
  box-sizing: border-box;
}
.zan-capsule__left {
  padding: 0 2px;
  color: #fff;
  background: #999;
  border-radius: 2px 0 0 2px;
  border: 1rpx solid #999;
}
.zan-capsule__right {
  padding: 0 5px;
  color: #999;
  border-radius: 0 2px 2px 0;
  border: 1rpx solid #999;
}

.zan-capsule--danger .zan-capsule__left {
  color: #fff;
  background: #f24544;
  border-color: #f24544;
}

.zan-capsule--danger .zan-capsule__right {
  color: #f24544;
  border-color: #f24544;
}
</style>
<template name="capsule">
  <view class="zan-capsule zan-capsule--{{options.type}}">
    <block wx:if="{{options.color}}">
      <view class="zan-capsule__left" style="background: {{ options.color }}; border-color: {{ options.color }}">{{ options.leftText }}</view>
      <view class="zan-capsule__right" style="color: {{ options.color }}; border-color: {{ options.color }}">{{ options.rightText }}</view>
    </block>
    <block wx:else>
      <view class="zan-capsule__left">{{ options.leftText }}</view>
      <view class="zan-capsule__right">{{ options.rightText }}</view>
    </block>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanCapsule extends wepy.component {
  props = {
    options: {
      type: Object,
      default: {
        type: '',
        color: '',
        leftText: '',
        rightText: ''
      }
    }
  }
  data = {}
  methods = {}
}
</script>


================================================
FILE: src/components/zan-dialog.wpy
================================================
<style lang="scss">
@import '../zanui/common';

/* 基础样式 */
.zan-dialog--container {
  position: fixed;
  top: 45%;
  left: 50%;
  width: 80%;
  height: 0;
  font-size: 16px;
  overflow: hidden;
  transition: all 0.2s linear;
  border-radius: 4px;
  background-color: #fff;
  transform: translate3d(-50%, -50%, 0);
  color: #333;
  opacity: 0;
}

.zan-dialog--mask {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.6);
  transition: 0.3s;
  display: none;
}

/* 弹出层内容 */
.zan-dialog__header {
  padding: 15px 0 0;
  text-align: center;
}

.zan-dialog__content {
  position: relative;
  padding: 15px 20px;
  line-height: 1.5;
  min-height: 40px;

  &::after {
    @include hairline;
    border-bottom-width: 1px;
  }
}

/* 在有标题时,需要减弱内容的存在感 */
.zan-dialog__content--title {
  color: #999;
  font-size: 14px;
}

.zan-dialog__footer {
  overflow: hidden;
}

.zan-dialog__button {
  line-height: 50px;
  height: 50px;
  padding: 0 5px;
  border-radius: 0;
  margin-bottom: 0;

  &::after {
    border-width: 0;
    border-radius: 0;
  }
}

/* 展示时,样式重置 */
.zan-dialog--show .zan-dialog--container {
  opacity: 1;
  height: auto;
}

.zan-dialog--show .zan-dialog--mask {
  display: block;
}

/* 水平/垂直布局 */
.zan-dialog__footer--horizon {
  display: flex;
}

.zan-dialog__footer--horizon .zan-dialog__button {
  flex: 1;

  &::after {
    border-right-width: 1px;
  }

  &:last-child::after {
    border-right-width: 0;
  }
}

.zan-dialog__footer--vertical .zan-dialog__button {
  flex: 1;

  &::after {
    border-bottom-width: 1px;
  }

  &:last-child::after {
    border-bottom-width: 0;
  }
}
</style>
<template>
  <view class="zan-dialog {{ zanDialog.show ? 'zan-dialog--show' : '' }}">
    <view class="zan-dialog--mask"></view>
    <view class="zan-dialog--container">
      <view
        wx:if="{{ zanDialog.title }}"
        class="zan-dialog__header">{{ zanDialog.title }}</view>
      <view
        class="zan-dialog__content {{ zanDialog.title ? 'zan-dialog__content--title' : '' }}">{{ zanDialog.content }}</view>
      <view
        class="zan-dialog__footer {{ zanDialog.buttonsShowVertical ? 'zan-dialog__footer--vertical' : 'zan-dialog__footer--horizon' }}">
        <block wx:for="{{ zanDialog.buttons }}" wx:key="{{ item.text }}-{{ item.type }}">
          <button
            class="zan-dialog__button zan-btn"
            data-type="{{ item.type }}"
            catchtap="handleZanDialogButtonClick"
            style="color: {{ item.color || '#333' }}">{{ item.text }}</button>
        </block>
      </view>
    </view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanDialog extends wepy.component {
  props = {}
  data = {
    zanDialog: {},
    animationData: {}
  }
  methods = {
    showZanDialog(options = {}, e) {
      const {
        // 自定义 btn 列表
        // { type: 按钮类型,回调时以此作为区分依据,text: 按钮文案, color: 按钮文字颜色 }
        buttons = [],
        // 标题
        title = '',
        // 内容
        content = ' ',
        // 按钮是否展示为纵向
        buttonsShowVertical = false,
        // 是否展示确定
        showConfirm = true,
        // 确认按钮文案
        confirmText = '确定',
        // 确认按钮颜色
        confirmColor = '#3CC51F',
        // 是否展示取消
        showCancel = false,
        // 取消按钮文案
        cancelText = '取消',
        // 取消按钮颜色
        cancelColor = '#333'
      } = options

      // 处理默认按钮的展示
      // 纵向排布确认按钮在上方
      let showCustomBtns = false
      if (buttons.length === 0) {
        if (showConfirm) {
          buttons.push({
            type: 'confirm',
            text: confirmText,
            color: confirmColor
          })
        }

        if (showCancel) {
          const cancelButton = {
            type: 'cancel',
            text: cancelText,
            color: cancelColor
          }
          if (buttonsShowVertical) {
            buttons.push(cancelButton)
          } else {
            buttons.unshift(cancelButton)
          }
        }
      } else {
        showCustomBtns = true
      }

      return new Promise((resolve, reject) => {
        this.zanDialog = {
          show: true,
          showCustomBtns,
          buttons,
          title,
          content,
          buttonsShowVertical,
          showConfirm,
          confirmText,
          confirmColor,
          showCancel,
          cancelText,
          cancelColor,
          // 回调钩子
          resolve,
          reject
        }
        this.$apply()
      })
    },

    handleZanDialogButtonClick(e) {
      const _f = function() {}
      const { currentTarget = {} } = e
      const { dataset = {} } = currentTarget

      // 获取当次弹出框的信息
      const zanDialogData = this.zanDialog || {}
      const { resolve = _f, reject = _f } = zanDialogData

      // 重置 zanDialog 里的内容
      this.zanDialog = Object.assign(this.zanDialog, { show: false })

      // 自定义按钮,全部 resolve 形式返回,根据 type 区分点击按钮
      if (zanDialogData.showCustomBtns) {
        resolve({
          type: dataset.type
        })
        return
      }

      // 默认按钮,确认为 resolve,取消为 reject
      if (dataset.type === 'confirm') {
        resolve({
          type: 'confirm'
        })
      } else {
        reject({
          type: 'cancel'
        })
      }
    }
  }
}
</script>


================================================
FILE: src/components/zan-field.wpy
================================================
<style lang="scss">
@import '../zanui/cell.scss';

.zan-field {
  padding: 7px 15px;
  color: #333;
}

.zan-field--wrapped {
  margin: 0 15px;
  background-color: #fff;

  &::after {
    left: 0;
    border-width: 1px;
    border-radius: 4px;
  }
}

.zan-field--wrapped + .zan-field--wrapped {
  margin-top: 10px;
}

.zan-field--error {
  color: #f40;
}

/* 圆角输入框时,将边框也置红 */
.zan-field--wrapped.zan-field--error::after {
  border-color: #f40;
}

.zan-field__title {
  color: #333;
  min-width: 65px;
  padding-right: 10px;
}

.zan-field__input {
  flex: 1;
  line-height: 1.6;
  padding: 4px 0;
  min-height: 22px;
  height: auto;
  font-size: 14px;
}

.zan-field__placeholder {
  font-size: 14px;
}

.zan-field__input--right {
  text-align: right;
}
</style>
<template>
  <view class="zan-cell zan-field {{ options.error ? 'zan-field--error' : '' }} {{ options.mode === 'wrapped' ? 'zan-field--wrapped' : '' }}">
    <view
      wx:if="{{ options.title }}"
      class="zan-cell__hd zan-field__title">{{ options.title }}</view>
    <textarea
      wx:if="{{ options.type === 'textarea' }}"
      auto-height
      name="{{ options.name || componentId || '' }}"
      value="{{ options.value }}"
      placeholder="{{ options.placeholder }}"
      class="zan-field__input zan-cell__bd {{ options.right ? 'zan-field__input--right' : '' }}"
      placeholder-class="zan-field__placeholder"
      bindinput="handleZanFieldChange"
      bindfocus="handleZanFieldFocus"
      bindblur="handleZanFieldBlur"
      data-component-id="{{ componentId || '' }}"></textarea>
    <input
      wx:else
      type="{{ options.inputType || 'text' }}"
      name="{{ options.name || componentId || '' }}"
      value="{{ options.value }}"
      placeholder="{{ options.placeholder }}"
      class="zan-field__input zan-cell__bd {{ options.right ? 'zan-field__input--right' : '' }}"
      placeholder-class="zan-field__placeholder"
      bindinput="handleZanFieldChange"
      bindfocus="handleZanFieldFocus"
      bindblur="handleZanFieldBlur"
      data-component-id="{{ componentId || '' }}"/>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanField extends wepy.component {
  props = {
    options: {
      type: Object,
      default: {
        right: true,
        error: true,
        name: '',
        value: '',
        type: 'textarea',
        mode: 'wrapped',
        title: '消费总额',
        inputType: 'number',
        placeholder: '询问收银员后输入'
      }
    },
    componentId: String
  }
  data = {}
  methods = {
    clear() {
      this.options.value = '  '
      this.$apply()
      this.options.value = ''
      this.$apply()
    },
    handleZanFieldChange(event) {
      event.componentId = this.componentId

      console.info('[zan:field:change]', event)

      return this.$emit('zanFieldChange', event)
    },

    handleZanFieldFocus(event) {
      event.componentId = this.componentId

      console.info('[zan:field:focus]', event)

      return this.$emit('zanFieldFocus', event)
    },

    handleZanFieldBlur(event) {
      event.componentId = this.componentId

      console.info('[zan:field:blur]', event)

      return this.$emit('zanFieldBlur', event)
    }
  }
}
</script>


================================================
FILE: src/components/zan-loadmore.wpy
================================================
<style lang="scss">
@import '../zanui/common';

.zan-loadmore {
  position: relative;
  width: 65%;
  margin: 21px auto;
  line-height: 20px;
  font-size: 14px;
  text-align: center;
  vertical-align: middle;
}

.zan-loading {
  width: 20px;
  height: 20px;
  display: inline-block;
  vertical-align: middle;
  animation: weuiLoading 1s steps(12, end) infinite;
  background: transparent
    url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iciIgd2lkdGg9JzEyMHB4JyBoZWlnaHQ9JzEyMHB4JyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj4KICAgIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSJub25lIiBjbGFzcz0iYmsiPjwvcmVjdD4KICAgIDxyZWN0IHg9JzQ2LjUnIHk9JzQwJyB3aWR0aD0nNycgaGVpZ2h0PScyMCcgcng9JzUnIHJ5PSc1JyBmaWxsPScjRTlFOUU5JwogICAgICAgICAgdHJhbnNmb3JtPSdyb3RhdGUoMCA1MCA1MCkgdHJhbnNsYXRlKDAgLTMwKSc+CiAgICA8L3JlY3Q+CiAgICA8cmVjdCB4PSc0Ni41JyB5PSc0MCcgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHJ4PSc1JyByeT0nNScgZmlsbD0nIzk4OTY5NycKICAgICAgICAgIHRyYW5zZm9ybT0ncm90YXRlKDMwIDUwIDUwKSB0cmFuc2xhdGUoMCAtMzApJz4KICAgICAgICAgICAgICAgICByZXBlYXRDb3VudD0naW5kZWZpbml0ZScvPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyM5Qjk5OUEnCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSg2MCA1MCA1MCkgdHJhbnNsYXRlKDAgLTMwKSc+CiAgICAgICAgICAgICAgICAgcmVwZWF0Q291bnQ9J2luZGVmaW5pdGUnLz4KICAgIDwvcmVjdD4KICAgIDxyZWN0IHg9JzQ2LjUnIHk9JzQwJyB3aWR0aD0nNycgaGVpZ2h0PScyMCcgcng9JzUnIHJ5PSc1JyBmaWxsPScjQTNBMUEyJwogICAgICAgICAgdHJhbnNmb3JtPSdyb3RhdGUoOTAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNBQkE5QUEnCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgxMjAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNCMkIyQjInCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgxNTAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNCQUI4QjknCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgxODAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNDMkMwQzEnCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgyMTAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNDQkNCQ0InCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgyNDAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNEMkQyRDInCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgyNzAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNEQURBREEnCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgzMDAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0PgogICAgPHJlY3QgeD0nNDYuNScgeT0nNDAnIHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyByeD0nNScgcnk9JzUnIGZpbGw9JyNFMkUyRTInCiAgICAgICAgICB0cmFuc2Zvcm09J3JvdGF0ZSgzMzAgNTAgNTApIHRyYW5zbGF0ZSgwIC0zMCknPgogICAgPC9yZWN0Pgo8L3N2Zz4=)
    no-repeat;
  -webkit-background-size: 100%;
  background-size: 100%;
}

.zan-loadmore .zan-loading {
  margin-right: 4px;
}

.zan-loadmore__tips {
  display: inline-block;
  vertical-align: middle;
  height: 20px;
  line-height: 20px;
}

.zan-loadmore--nodata,
.zan-loadmore--nomore {
  color: #999;

  &::after {
    @include hairline;
    border-top-width: 1px;
  }
}

.zan-loadmore--nodata {
  margin-top: 120px;
}

.zan-loadmore--nodata .zan-loadmore__tips {
  position: relative;
  top: -11px;
  background: #f9f9f9;
  padding: 0 6px;
  z-index: 1;
}

.zan-loadmore--nomore .zan-loadmore__tips {
  position: relative;
  top: -11px;
  background: #f9f9f9;
  padding: 0 6px;
  z-index: 1;
}

.zan-loadmore__dot {
  position: absolute;
  left: 50%;
  top: 10px;
  margin-left: -2px;
  margin-top: -2px;
  content: ' ';
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-color: #e5e5e5;
  display: inline-block;
  vertical-align: middle;
}
</style>
<template>
<block>
  <block wx:if="{{nomore}}">
    <view class="zan-loadmore zan-loadmore--nomore">
      <view class="zan-loadmore__tips">
        <view class="zan-loadmore__dot"></view>
      </view>
    </view>
  </block>

  <block wx:elif="{{nodata}}">
    <view class="zan-loadmore zan-loadmore--nodata">
      <view class="zan-loadmore__tips">{{ nodata_str }}</view>
    </view>
  </block>

  <block wx:elif="{{loading}}">
    <view class="zan-loadmore">
      <view class="zan-loading"></view>
      <view class="zan-loadmore__tips">加载中...</view>
    </view>
  </block>
</block>
</template>
<script>
import wepy from 'wepy'

export default class zanLoadmore extends wepy.component {
  props = {
    loading: {
      type: Boolean,
      default: false
    },
    nodata: {
      type: Boolean,
      default: false
    },
    nomore: {
      type: Boolean,
      default: false
    },
    nodata_str: {
      type: String,
      default: '暂无数据'
    }
  }
  methods = {}
}
</script>


================================================
FILE: src/components/zan-noticebar.wpy
================================================
<style lang="scss">
.zan-noticebar {
  color: #f60;
  padding: 9px 10px;
  font-size: 12px;
  line-height: 1.5;
  background-color: #fff7cc;
}
</style>
<template>
  <view class="zan-noticebar">
    <view
      id="{{ componentId }}__content-wrap"
      style="height: 18px; overflow: hidden; position: relative;"
    >
      <view
        animation="{{ animationData }}"
        id="{{ componentId }}__content"
        style="position: absolute; white-space: nowrap;"
      >
        {{ text }}
      </view>
    </view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanNoticebar extends wepy.component {
  props = {
    componentId: String,
    text: String
  }
  data = {
    animationData: {},
    currentComponent: {}
  }
  methods = {
    initZanNoticeBarScroll() {
      let componentId = this.componentId
      let currentComponent = {
        width: undefined,
        wrapWidth: undefined,
        animation: null,
        resetAnimation: null
      }
      wx
        .createSelectorQuery()
        .select(`#${componentId}__content`)
        .boundingClientRect(rect => {
          if (rect.width) {
            currentComponent.width = rect.width
            wx
              .createSelectorQuery()
              .select(`#${componentId}__content-wrap`)
              .boundingClientRect(rect => {
                currentComponent.wrapWidth = rect.width
                if (currentComponent.wrapWidth < currentComponent.width) {
                  let mstime = currentComponent.width / 40 * 1000
                  currentComponent.animation = wx.createAnimation({
                    duration: mstime,
                    timingFunction: 'linear'
                  })
                  currentComponent.resetAnimation = wx.createAnimation({
                    duration: 0,
                    timingFunction: 'linear'
                  })
                  this.currentComponent = currentComponent
                  this.methods.scrollZanNoticeBar.call(this, componentId, mstime)
                }
              })
              .exec()
          } else {
            console.warn('页面缺少 noticebar 元素')
          }
        })
        .exec()
    },

    scrollZanNoticeBar(componentId, mstime) {
      let currentComponent = this.currentComponent
      let resetAnimationData = currentComponent.resetAnimation.translateX(currentComponent.wrapWidth).step()
      this.animationData = resetAnimationData.export()
      this.$apply()
      let aninationData = currentComponent.animation.translateX(-mstime * 40 / 1000).step()
      setTimeout(() => {
        this.animationData = aninationData.export()
        this.$apply()
      }, 100)

      setTimeout(() => {
        this.methods.scrollZanNoticeBar.call(this, componentId, mstime)
      }, mstime)
    }
  }
}
</script>


================================================
FILE: src/components/zan-popup.wpy
================================================
<style lang="scss">
.zan-popup {
  visibility: hidden;
}
.zan-popup--show {
  visibility: visible;
}
.zan-popup__mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  background: rgba(0, 0, 0, 0.7);
  display: none;
}
.zan-popup__container {
  position: fixed;
  left: 50%;
  top: 50%;
  background: #fff;
  transform: translate3d(-50%, -50%, 0);
  transform-origin: center;
  transition: all 0.4s ease;
  z-index: 11;
  opacity: 0;
}
.zan-popup--show .zan-popup__container {
  opacity: 1;
}
.zan-popup--show .zan-popup__mask {
  display: block;
}

/* 左侧popup */
.zan-popup--left .zan-popup__container {
  left: 0;
  top: auto;
  transform: translate3d(-100%, 0, 0);
}
.zan-popup--show.zan-popup--left .zan-popup__container {
  transform: translate3d(0, 0, 0);
}

/* 右侧popup */
.zan-popup--right .zan-popup__container {
  right: 0;
  top: auto;
  left: auto;
  transform: translate3d(100%, 0, 0);
}
.zan-popup--show.zan-popup--right .zan-popup__container {
  transform: translate3d(0, 0, 0);
}

/* 底部popup */
.zan-popup--bottom .zan-popup__container {
  top: auto;
  left: auto;
  bottom: 0;
  transform: translate3d(0, 100%, 0);
}
.zan-popup--show.zan-popup--bottom .zan-popup__container {
  transform: translate3d(0, 0, 0);
}

/* 顶部popup */
.zan-popup--top .zan-popup__container {
  top: 0;
  left: auto;
  transform: translate3d(0, -100%, 0);
}
.zan-popup--show.zan-popup--top .zan-popup__container {
  transform: translate3d(0, 0, 0);
}

.popup-example--center {
  border-radius: 4px;
}

.popup-example--right .zan-popup__container {
  top: 0;
  bottom: 0;
}

.popup-example--left .zan-popup__container {
  top: 0;
  bottom: 0;
}

.popup-example--top .zan-popup__container {
  left: 0;
  right: 0;
  padding: 15px;
  background-color: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: 16px;
}
.popup-example--top .zan-popup__mask {
  opacity: 0;
}

.popup-example--bottom .zan-popup__container {
  left: 0;
  right: 0;
}
</style>
<template>
  <view class="zan-popup {{direction ? 'popup-example--' + direction + ' zan-popup--' + direction : ''}} {{ showPopup ? 'zan-popup--show' : ''}}">
    <view class="zan-popup__mask" bindtap="togglePopup"></view>
    <view class="zan-popup__container {{direction ? '' : 'popup-example--center'}}">
      <slot></slot>
    </view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanToast extends wepy.component {
  props = {
    direction: {
      type: String,
      default: ''
    }
  }
  data = {
    showPopup: false
  }
  methods = {
    togglePopup() {
      this.showPopup = !this.showPopup
      this.$apply()
    }
  }
}
</script>


================================================
FILE: src/components/zan-select.wpy
================================================
<style lang="scss">
@import '../zanui/cell.scss';
.zan-select__list .zan-select__radio {
  display: none;
}
</style>
<template>
<block>
  <radio-group
    class="zan-select__list"
    name="{{ name || componentId || '' }}"
    bindchange="handleZanSelectChange"
    data-component-id="{{ componentId }}"
  >
    <label wx:for="{{ items }}" wx:key="value">
      <view class="zan-cell">
        <radio class="zan-select__radio" value="{{ item.value }}" checked="{{ item.value === checkedValue }}"/>
        <view
          class="zan-cell__bd"
          style="{{ 'padding-left: ' + item.padding * 10 + 'px;' + ' color: ' + activeColor }}"
        >{{ item.name }}</view>
        <view wx:if="{{ item.value === checkedValue }}" class="zan-cell__ft">
          <icon type="success_no_circle" color="{{ activeColor }}" size="14"></icon>
        </view>
      </view>
    </label>
  </radio-group>
</block>
</template>
<script>
import wepy from 'wepy'

export default class zanSelect extends wepy.component {
  props = {
    items: Object,
    name: {
      type: String,
      default: ''
    },
    activeColor: {
      type: String,
      default: '#ff4444'
    },
    checkedValue: Number,
    componentId: String
  }
  data = {}
  methods = {
    handleZanSelectChange(e) {
      let value = e.detail.value
      console.info('[zan:Select:change]', value, e)
      this.$emit('zanSelectChange', value)
    }
  }
  computed = {}
}
</script>


================================================
FILE: src/components/zan-stepper.wpy
================================================
<style lang="less">
.zan-stepper {
  color: #666;
}

.zan-stepper view {
  display: inline-block;
  line-height: 20px;
  padding: 5px 0;
  text-align: center;
  min-width: 40px;
  box-sizing: border-box;
  vertical-align: middle;
  font-size: 12px;
  border: 1rpx solid #999;
}

.zan-stepper .zan-stepper__minus {
  border-right: none;
  border-radius: 2px 0 0 2px;
}

.zan-stepper .zan-stepper__text {
  border: 1rpx solid #999;
  display: inline-block;
  text-align: center;
  vertical-align: middle;
  height: 30px;
  width: 40px;
  font-size: 12px;
  line-height: 30px;
}

.zan-stepper .zan-stepper__plus {
  border-left: none;
  border-radius: 0 2px 2px 0;
}

.zan-stepper .zan-stepper--disabled {
  background: #f8f8f8;
  color: #bbb;
  border-color: #e8e8e8;
}

.zan-stepper--small view {
  min-width: 36px;
  line-height: 18px;
}

.zan-stepper--small .zan-stepper__text {
  width: 36px;
  line-height: 28px;
  height: 28px;
}
</style>
<template>
  <view class="zan-stepper {{ size === 'small' ? 'zan-stepper--small' : '' }}">
    <view class="zan-stepper__minus {{ stepper <= min ? 'zan-stepper--disabled' : '' }}" data-component-id="{{ componentId }}" data-stepper="{{ stepper }}" data-disabled="{{ stepper <= min }}" bindtap="handleZanStepperMinus">-</view>
    <input class="zan-stepper__text {{ min >= max ? 'zan-stepper--disabled' : '' }}" type="number" data-component-id="{{ componentId }}" data-min="{{ min }}" data-max="{{ max }}" value="{{ stepper }}" disabled="{{ min >= max }}" bindblur="handleZanStepperBlur"></input>
    <view class="zan-stepper__plus {{ stepper >= max ? 'zan-stepper--disabled' : '' }}" data-component-id="{{ componentId }}" data-stepper="{{ stepper }}" data-disabled="{{ stepper >= max }}" bindtap="handleZanStepperPlus">+</view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanStepper extends wepy.component {
  props = {
    stepper: {
      type: Number,
      default: 0
    },
    min: {
      type: Number,
      default: 0
    },
    max: {
      type: Number,
      default: 0
    },
    size: {
      type: String,
      default: ''
    },
    componentId: String
  }
  data = {}
  methods = {
    handleZanStepperMinus(e) {
      this.handle(e, -1)
    },

    handleZanStepperPlus(e) {
      this.handle(e, +1)
    },

    handleZanStepperBlur(e) {
      let dataset = e.currentTarget.dataset
      let componentId = dataset.componentId
      let max = +dataset.max
      let min = +dataset.min
      let value = e.detail.value

      if (!value) {
        setTimeout(() => {
          this.callback(componentId, min)
        }, 16)
        this.callback(componentId, value)
        return '' + value
      }

      value = +value
      if (value > max) {
        value = max
      } else if (value < min) {
        value = min
      }

      this.callback(componentId, value)

      return '' + value
    }
  }

  handle(e, num) {
    let dataset = e.currentTarget.dataset
    let componentId = dataset.componentId
    let disabled = dataset.disabled
    let stepper = +dataset.stepper

    if (disabled) return null

    this.callback(componentId, stepper + num)
  }

  callback(componentId, stepper) {
    stepper = +stepper
    let e = { componentId, stepper }
    console.info('[zan:stepper:change]', e)

    this.$emit('zanStepperChange', e)
  }
}
</script>


================================================
FILE: src/components/zan-steps.wpy
================================================
<style lang="scss">
.zan-steps--steps.zan-steps--5 .zan-steps__step {
  width: 25%;
}

.zan-steps--steps.zan-steps--4 .zan-steps__step {
  width: 33%;
}

.zan-steps--steps.zan-steps--3 .zan-steps__step {
  width: 50%;
}

.zan-steps--steps .zan-steps__step {
  position: relative;
  float: left;
  padding-bottom: 25px;
  color: #b1b1b1;
}

.zan-steps--steps .zan-steps__title {
  transform: translateX(-50%);
  font-size: 10px;
  text-align: center;
}

.zan-steps--steps .zan-steps__icons {
  position: absolute;
  top: 30px;
  left: -10px;
  padding: 0 8px;
  background-color: #fff;
  z-index: 10;
}

.zan-steps--steps .zan-steps__circle {
  display: block;
  position: relative;
  width: 5px;
  height: 5px;
  background-color: #e5e5e5;
  border-radius: 50%;
}

.zan-steps--steps .zan-steps__line {
  position: absolute;
  left: 0px;
  top: 32px;
  width: 100%;
  height: 1px;
  background-color: #e5e5e5;
}

/* 已完成的steps */
.zan-steps--steps .zan-steps__step--done {
  color: #333;
}

.zan-steps--steps .zan-steps__step--done .zan-steps__line {
  background-color: #06bf04;
}

.zan-steps--steps .zan-steps__step--done .zan-steps__circle {
  width: 5px;
  height: 5px;
  background-color: #09bb07;
}

/* 正在进行中的steps */
.zan-steps--steps .zan-steps__step--cur .zan-steps__icons {
  top: 25px;
  left: -14px;
}

.zan-steps--steps .zan-steps__step--cur .zan-steps__circle {
  width: 13px;
  height: 13px;
  background-image: url('https://b.yzcdn.cn/v2/image/wap/success_small@2x.png');
  background-size: 13px 13px;
}

.zan-steps--steps .zan-steps__step--cur .zan-steps__line {
  background-color: #e5e5e5;
}

/* 各种不同位置的 */
.zan-steps--steps .zan-steps__step--first-child .zan-steps__title {
  margin-left: 0;
  transform: none;
  text-align: left;
}

.zan-steps--steps .zan-steps__step--first-child .zan-steps__icons {
  left: -7px;
}

.zan-steps--steps .zan-steps__step--last-child {
  position: absolute;
  right: 0;
  top: 0;
  text-align: right;
}

.zan-steps--steps .zan-steps__step--last-child .zan-steps__title {
  transform: none;
  text-align: right;
}

.zan-steps--steps .zan-steps__step--last-child .zan-steps__icons {
  left: auto;
  right: -6px;
}

.zan-steps--steps .zan-steps__step--last-child .zan-steps__line {
  display: none;
}

/* 有描述的step */
.zan-steps--steps .zan-steps__step--db-title {
  min-height: 29px;
}

.zan-steps--steps .zan-steps__step--db-title .zan-steps__line {
  top: 45px;
}

.zan-steps--steps .zan-steps__step--db-title .zan-steps__icons {
  top: 43px;
}

.zan-steps--steps .zan-steps__step--db-title.zan-steps__step--cur .zan-steps__icons {
  top: 39px;
}

.zan-steps--vsteps {
  color: #999;
  font-size: 14px;
}

.zan-steps--vsteps .zan-steps__step {
  position: relative;
  padding: 15px 0;
}

.zan-steps--vsteps .zan-steps__step--done {
  color: #44bb00;
}

.zan-steps--vsteps .zan-steps__line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 7px;
  width: 1px;
  background-color: #e5e5e5;
}

.zan-steps--vsteps .zan-steps__title {
  display: inline-block;
  line-height: 20px;
  padding-left: 27px;
}

.zan-steps--vsteps .zan-steps__title--desc {
  padding-left: 3px;
}

.zan-steps--vsteps .zan-steps__icons {
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  padding: 3px 0;
  background-color: #fff;
}

.zan-steps--vsteps .zan-steps__circle {
  width: 5px;
  height: 5px;
  background-color: #cacaca;
  border-radius: 10px;
}

.zan-steps--vsteps .zan-steps__step--done .zan-steps__circle {
  width: 5px;
  height: 5px;
  background-color: #09bb07;
}

.zan-steps--vsteps .zan-steps__step--cur .zan-steps__circle {
  width: 13px;
  height: 13px;
  background: transparent url('https://b.yzcdn.cn/v2/image/wap/success_small@2x.png');
  background-size: 13px 13px;
  border-radius: 0;
}

.zan-steps--vsteps .zan-steps__icon--active {
  width: 13px;
  height: 13px;
}

.zan-steps--vsteps .zan-steps__step--first-child .zan-steps__title::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 50%;
  left: 7px;
  width: 1px;
  background-color: #fff;
  z-index: 1;
}

.zan-steps--vsteps .zan-steps__step--last-child .zan-steps__title::after {
  content: '';
  position: absolute;
  top: 50%;
  bottom: 0%;
  left: 7px;
  width: 1px;
  background-color: #fff;
  z-index: 1;
}

.zan-steps {
  position: relative;
}
</style>
<template>
  <view class="zan-steps zan-steps--{{ type == 'vertical' ? 'vsteps' : 'steps' }} zan-steps--{{ steps.length }} {{ className }}">
    <view
      wx:for="{{ steps }}" wx:for-item="step" wx:key="unique" wx:for-index="index"
      class="zan-steps__step {{ hasDesc ? 'zan-steps__step--db-title' : '' }} {{ index == 0 ? 'zan-steps__step--first-child' : '' }} {{ index == steps.length - 1 ? 'zan-steps__step--last-child' : '' }} {{ step.done ? 'zan-steps__step--done' : '' }} {{ step.current ? 'zan-steps__step--cur' : '' }}"
    >
      <view class="zan-steps__title">{{ step.text }}</view>
      <view wx:if="{{ hasDesc && step.desc }}" class="zan-steps__title zan-steps__title--desc">{{ step.desc }}</view>
      <view class="zan-steps__icons">
        <view class="zan-steps__circle"></view>
      </view>
      <view class="zan-steps__line"></view>
    </view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanSteps extends wepy.component {
  props = {
    steps: Object,
    type: String,
    hasDesc: {
      type: Boolean,
      default: false
    },
    className: {
      type: String,
      default: ''
    }
  }
  data = {}
  methods = {}
}
</script>


================================================
FILE: src/components/zan-switch.wpy
================================================
<style lang="scss">
.zan-switch {
  position: relative;
  display: inline-block;
  width: 52px;
  height: 32px;
  vertical-align: middle;
  box-sizing: border-box;
  border-radius: 16px;
  background: #44db5e;
  border: 1px solid #44db5e;
}

.zan-switch__circle {
  position: absolute;
  top: 0;
  left: 0;
  width: 30px;
  height: 30px;
  display: inline-block;
  background: #fff;
  border-radius: 15px;
  box-sizing: border-box;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1),
    0 3px 3px 0 rgba(0, 0, 0, 0.05);
  transition: transform 0.35s cubic-bezier(0.45, 1, 0.4, 1);
  z-index: 2;
}

.zan-switch__bg {
  position: absolute;
  top: -1px;
  left: -1px;
  width: 52px;
  height: 32px;
  background: #fff;
  border-radius: 26px;
  display: inline-block;
  border: 1px solid #e5e5e5;
  box-sizing: border-box;
  transition: transform 0.35s cubic-bezier(0.45, 1, 0.4, 1);
  transform: scale(0);
  transform-origin: 36px 16px;
}

.zan-switch--on .zan-switch__circle {
  transform: translateX(20px);
}

.zan-switch--off .zan-switch__bg {
  transform: scale(1);
}

.zan-swtich--disabled {
  opacity: 0.4;
}

.zan-switch__loading {
  position: absolute;
  left: 7px;
  top: 7px;
  width: 16px;
  height: 16px;
  background: url(https://img.yzcdn.cn/public_files/2017/02/24/9acec77d91106cd15b8107c4633d9155.png) no-repeat;
  background-size: 16px 16px;
  animation: zan-switch-loading 0.8s infinite linear;
}

@keyframes zan-switch-loading {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}
</style>
<template>
  <view class="zan-switch zan-switch--{{ checked ? 'on' : 'off' }} {{ disabled ? 'zan-swtich--disabled' : '' }}" data-checked="{{ checked }}" data-loading="{{ loading }}" data-disabled="{{ disabled }}" data-component-id="{{ componentId }}" @tap="handleZanSwitchChange">
    <view class="zan-switch__circle">
      <view hidden="{{ !loading }}" class="zan-switch__loading"></view>
    </view>
    <view class="zan-switch__bg"></view>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanSwitch extends wepy.component {
  props = {
    checked: {
      type: Boolean,
      default: false
    },
    loading: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    componentId: String
  }
  data = {}
  methods = {
    handleZanSwitchChange(e) {
      let dataset = e.currentTarget.dataset
      let { checked, loading, disabled, componentId } = dataset

      if (loading || disabled) return

      console.info('[zan:switch:change]', { componentId, checked: !checked })

      this.$emit('zanSwitchChange')
    }
  }
}
</script>


================================================
FILE: src/components/zan-tab.wpy
================================================
<style lang="scss">
.zan-tab {
  height: 45px;
}
.zan-tab__bd {
  width: 750rpx;
  display: flex;
  flex-direction: row;
  border-bottom: 1rpx solid #e5e5e5;
  background: #fff;
}
.zan-tab__bd--fixed {
  position: fixed;
  top: 0;
  z-index: 2;
}
.zan-tab__item {
  flex: 1;
  display: inline-block;
  padding: 0 10px;
  line-height: 0;
  box-sizing: border-box;
  overflow: hidden;
  text-align: center;
}

.zan-tab__title {
  display: inline-block;
  max-width: 100%;
  height: 44px;
  line-height: 44px;
  overflow: hidden;
  text-overflow: ellipsis;
  box-sizing: border-box;
  word-break: keep-all;
  font-size: 14px;
  color: #666;
}

.zan-tab__item--selected .zan-tab__title {
  color: #f44;
  border-bottom: 2px solid #f44;
}

.zan-tab__bd--scroll {
  display: block;
  white-space: nowrap;
}
.zan-tab__bd--scroll .zan-tab__item {
  min-width: 80px;
}
</style>
<template>
  <view class="zan-tab">
    <block wx:if="{{options.scroll}}">
      <scroll-view class="zan-tab__bd zan-tab__bd--scroll {{ fixed ? 'zan-tab__bd--fixed' : '' }}" scroll-x="true" style="height: {{ options.height ? options.height + 'px' : 'auto' }}">
        <view wx:for="{{options.list}}" wx:key="id" class="zan-tab__item {{options.selectedId == item.id ? 'zan-tab__item--selected' : ''}}" data-component-id="{{componentId}}" data-item-id="{{item.id}}" @tap="handleZanTabChange">
          <view class="zan-tab__title">{{item.title}}</view>
        </view>
      </scroll-view>
    </block>
    <block wx:else>
      <view class="zan-tab__bd {{fixed ? 'zan-tab__bd--fixed' : ''}}">
        <view wx:for="{{options.list}}" wx:key="id" class="zan-tab__item {{options.selectedId == item.id ? 'zan-tab__item--selected' : ''}}" data-component-id="{{componentId}}" data-item-id="{{item.id}}" @tap="handleZanTabChange">
          <view class="zan-tab__title">{{item.title}}</view>
        </view>
      </view>
    </block>
  </view>
</template>
<script>
import wepy from 'wepy'

export default class zanTab extends wepy.component {
  props = {
    options: {
      type: Object,
      default: {
        list: [
          {
            id: '1',
            title: '商品1'
          },
          {
            id: '2',
            title: '商品2'
          },
          {
            id: '3',
            title: '商品3'
          },
          {
            id: '4',
            title: '商品4'
          },
          {
            id: '5',
            title: '商品5'
          },
          {
            id: '6',
            title: '商品6'
          }
        ],
        selectedId: '1',
        scroll: true,
        height: 45
      }
    },
    componentId: String
  }
  data = {}
  methods = {
    handleZanTabChange(e) {
      let { componentId, itemId: selectedId } = e.currentTarget.dataset
      this.options.selectedId = selectedId
      this.$apply()
      console.info('[zan:tab:change]', { componentId, selectedId })
      this.$emit('zanTabChange', { selectedId })
    }
  }
}
</script>


================================================
FILE: src/components/zan-toast.wpy
================================================
<style lang="less">
.zan-toast {
  position: fixed;
  top: 35%;
  left: 20%;
  transform: translateZ(0) translateY(-100%);
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: 14px;
  width: 60%;
  line-height: 1.5em;
  margin: 0 auto;
  box-sizing: border-box;
  padding: 10px;
  text-align: center;
  border-radius: 4px;
  z-index: 100;
}
</style>
<template>
  <view class="zan-toast" wx:if="{{ zanToast.show }}" @tap="clearZanToast">
    {{ zanToast.title }}</view>
</template>
<script>
import wepy from 'wepy'

export default class zanToast extends wepy.component {
  props = {}
  data = {
    zanToast: {}
  }
  methods = {
    showZanToast({title, timeout}) {
      var zanToast = this.zanToast || {}
      clearTimeout(zanToast.timer)

      // 弹层设置~
      this.zanToast = {
        show: true,
        title
      }
      this.$apply()

      var timer = setTimeout(() => {
        this.methods.clearZanToast.call(this)
      }, timeout || 3000)

      this.zanToast.timer = timer
      this.$apply()
    },
    clearZanToast() {
      var zanToast = this.zanToast || {}
      clearTimeout(zanToast.timer)

      this.zanToast.show = false
      this.$apply()
    }
  }
}
</script>


================================================
FILE: src/components/zan-toptips.wpy
================================================
<style lang="scss">
.zan-toptips {
  display: block;
  position: fixed;
  transform: translateY(-100%);
  width: 100%;
  min-height: 32px; /* 至少有一行的高度,保证第一次动画显示正常 */
  top: 0;
  line-height: 2.3;
  font-size: 14px;
  text-align: center;
  color: #fff;
  background-color: #e64340;
  z-index: 110;
}
</style>
<template>
  <view animation="{{animationData}}" class="zan-toptips"> {{ topTips.content }} </view>
</template>
<script>
import wepy from 'wepy'

export default class zanToptips extends wepy.component {
  props = {}
  data = {
    topTips: {},
    animationData: {}
  }
  methods = {
    showZanTopTips({ content = '', options = {} }, event) {
      console.log('showZanTopTips', content, options)
      let topTips = this.topTips || {}
      // 如果已经有一个计时器在了,就清理掉先
      if (topTips.timer) {
        clearTimeout(topTips.timer)
        topTips.timer = undefined
      }

      if (typeof options === 'number') {
        options = {
          duration: options
        }
      }

      // options参数默认参数扩展
      options = Object.assign(
        {
          duration: 3000
        },
        options
      )

      // 原生动画
      let animation = wepy.createAnimation({
        duration: 400,
        timingFunction: 'ease'
      })
      this.animation = animation

      const toggle = () => {
        wx
          .createSelectorQuery()
          .select('.zan-toptips')
          .boundingClientRect(rect => {
            this.topTips.show ? animation.translateY().step() : animation.translateY(-rect.height).step()
            this.animationData = animation.export()
            this.$apply()
          })
          .exec()
      }

      // 设置定时器,定时关闭topTips
      let timer = setTimeout(() => {
        this.topTips.show = false
        this.topTips.timer = undefined
        toggle()
      }, options.duration)

      // 展示出topTips
      this.topTips = {
        show: true,
        content,
        timer
      }
      toggle()
    }
  }
}
</script>


================================================
FILE: src/example/actionsheet.wpy
================================================
<style lang="css">
@import '/zanui/btn.wxss';
</style>

<template>
<block>
<view class="container">

  <view class="doc-title zan-hairline--bottom zan-hairline--bottom">ACTIONSHEET</view>

  <view class="zan-btns" style="margin-top: 30vh;">
    <button class="zan-btn" bindtap="toggleActionsheet">
      Actionsheet
    </button>
  </view>

</view>

<zanActionsheet componentId="baseActionsheet"/>
<zanToptips/>

</block>
</template>

<script>
import wepy from 'wepy'
import zanActionsheet from '../components/zan-actionsheet'
import zanToptips from '../components/zan-toptips'

export default class Actionsheet extends wepy.page {
  config = {
    navigationBarTitleText: 'Actionsheet 行动按钮'
  }
  components = {
    zanActionsheet,
    zanToptips
  }
  data = {}
  events = {}
  methods = {
    toggleActionsheet() {
      this.$invoke('zanActionsheet', 'showZanActionsheet', {
        cancelText: '关闭 Action',
        closeOnClickOverlay: true,
        actions: [
          {
            type: 'first',
            name: '选项1',
            subname: '选项描述语1',
            className: 'action-class',
            loading: false,
            asyncJob: function() {
              return new Promise((resolve, reject) => {
                setTimeout(() => {
                  resolve()
                }, 1500)
              })
            }
          },
          {
            type: 'second',
            name: '选项2',
            subname: '选项描述语2',
            className: 'action-class',
            loading: false
          },
          {
            type: 'share',
            name: '去分享',
            openType: 'share'
          }
        ]
      })
        .then(result => {
          this.$invoke('zanToptips', 'showZanTopTips', { content: result.type, options: 1000 })
        })
        .catch(e => {
          this.$invoke('zanToptips', 'showZanTopTips', { content: '行动取消', options: 1000 })
        })
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/badge.wpy
================================================
<style lang="css">
@import '/zanui/badge.wxss';

.demo {
  padding: 40px 0;
  display: flex;
}
.demo__item {
  flex: 1;
}
.demo__icon {
  margin: 0 auto;
  width: 48px;
  height: 48px;
  background: #ddd;
  border-radius: 4px;
}
</style>

<template>
  <view class="container">

    <view class="doc-title zan-hairline--bottom zan-hairline--bottom">BADGE</view>

    <view class="demo">
      <view class="demo__item">
        <view class="demo__icon zan-badge">
        </view>
      </view>
      <view class="demo__item">
        <view class="demo__icon zan-badge">
          <view class="zan-badge__count">9</view>
        </view>
      </view>
      <view class="demo__item">
        <view class="demo__icon zan-badge">
          <view class="zan-badge__count">19</view>
        </view>
      </view>
      <view class="demo__item">
        <view class="demo__icon zan-badge">
          <view class="zan-badge__count">99+</view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import wepy from 'wepy'
export default class Badge extends wepy.page {
  config = {
    navigationBarTitleText: 'Badge 徽章'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/btn.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/btn.wxss';
</style>

<template>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">BUTTON</view>

    <view class="zan-panel-title">普通按钮</view>
    <view class="zan-panel">
      <view class="zan-btns">
        <button class="zan-btn">取消订单</button>
        <button class="zan-btn zan-btn--primary">确认付款</button>
        <button class="zan-btn zan-btn--danger">确认付款</button>
        <button class="zan-btn zan-btn--warn">确认付款</button>
      </view>
    </view>

    <view class="zan-panel-title">大号按钮,没有边框线及圆角</view>
    <view class="zan-panel">
      <button class="zan-btn zan-btn--large zan-btn--primary">确认付款</button>
      <button class="zan-btn zan-btn--large zan-btn--warn">立即购买</button>
      <button class="zan-btn zan-btn--large zan-btn--danger">立即购买</button>
    </view>

    <view class="zan-panel-title">小号按钮</view>
    <view class="zan-panel" style="padding: 15px;">
      <button class="zan-btn zan-btn--small">取消订单</button>
      <button class="zan-btn zan-btn--small zan-btn--primary">确认付款</button>
    </view>

    <view class="zan-panel-title">迷你按钮</view>
    <view class="zan-panel" style="padding: 15px;">
      <button class="zan-btn zan-btn--mini zan-btn--plain">取消订单</button>
      <button class="zan-btn zan-btn--mini zan-btn--primary zan-btn--plain">确认付款</button>
      <button class="zan-btn zan-btn--mini zan-btn--warn zan-btn--plain">确认付款</button>
      <button class="zan-btn zan-btn--mini zan-btn--danger zan-btn--plain">确认付款</button>
    </view>

    <view class="zan-panel-title">Loading</view>
    <view class="zan-panel">
      <view class="zan-btns">
        <button class="zan-btn zan-btn--loading">取消订单</button>
        <button class="zan-btn zan-btn--loading zan-btn--primary">确认付款</button>
        <button class="zan-btn zan-btn--loading zan-btn--danger">确认付款</button>
        <button class="zan-btn zan-btn--loading zan-btn--warn">确认付款</button>
      </view>
    </view>

    <view class="zan-panel-title">Disabled</view>
    <view class="zan-panel">
      <view class="zan-btns">
        <button class="zan-btn zan-btn--disabled" disabled>取消订单</button>
        <button class="zan-btn zan-btn--disabled zan-btn--primary" disabled>确认付款</button>
        <button class="zan-btn zan-btn--disabled zan-btn--danger" disabled>确认付款</button>
        <button class="zan-btn zan-btn--disabled zan-btn--warn" disabled>确认付款</button>
      </view>
    </view>

  </view>
</template>

<script>
import wepy from 'wepy'
export default class Button extends wepy.page {
  config = {
    navigationBarTitleText: 'Button 按钮'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/capsule.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';

.zan-capsule + .zan-capsule {
  margin-left: 10px;
}
</style>

<template>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">CAPSULE</view>

    <view class="zan-panel-title">基本用法</view>
    <view class="zan-panel">
      <view class="zan-cell zan-cell--last-child">
        <zanCapsule1 :options="zanCapsule1" />
        <zanCapsule2 :options="zanCapsule2" />
      </view>
    </view>

    <view class="zan-panel-title">自定义颜色</view>
    <view class="zan-panel">
      <view class="zan-cell zan-cell--last-child">
        <zanCapsule3 :options="zanCapsule3" />
      </view>
    </view>

  </view>
</template>

<script>
import wepy from 'wepy'
import zanCapsule from '../components/zan-capsule'

export default class Capsule extends wepy.page {
  config = {
    navigationBarTitleText: 'Capsule 胶囊'
  }
  components = {
    zanCapsule1: zanCapsule,
    zanCapsule2: zanCapsule,
    zanCapsule3: zanCapsule
  }
  data = {
    zanCapsule1: {
      leftText: '1折',
      rightText: '限购一份'
    },
    zanCapsule2: {
      type: 'danger',
      leftText: '2折',
      rightText: '限购两份'
    },
    zanCapsule3: {
      color: '#38f',
      leftText: '3折',
      rightText: '限购三份'
    }
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/card.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/card.wxss';
@import '/zanui/color.wxss';
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">CARD</view>

  <view class="zan-panel">
    <view class="zan-card">
      <view class="zan-card__thumb">
        <image class="zan-card__img"
          src="https://img.yzcdn.cn/upload_files/2016/11/25/FpqPXlrMRjKwJs8VdTu3ZDJCj4j5.jpeg?imageView2/2/w/200/h/200/q/90/format/jpeg"
          mode="aspectFit"
        />
      </view>
      <view class="zan-card__detail">
        <view class="zan-card__detail-row">
          <view class="zan-card__right-col">¥ 999.99</view>
          <view class="zan-card__left-col zan-ellipsis--l2">
             红烧牛肉【虚拟商品】【有库存】【有sku】
          </view>
        </view>

        <view class="zan-card__detail-row zan-c-gray-darker">
          <view class="zan-card__right-col">x2</view>
          <view class="zan-card__left-col">
            3000克 50%
          </view>
        </view>

        <view class="zan-card__detail-row zan-c-gray-darker">
          <view class="zan-card__left-col zan-c-red">已发货</view>
        </view>
      </view>
    </view>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'

export default class Card extends wepy.page {
  config = {
    navigationBarTitleText: 'Card 卡片'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/cell.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';
@import '/zanui/icon.wxss';
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">CELL</view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">单行列表</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">单行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__icon zan-icon zan-icon-checked" style="color:#38f;"></view>
      <view class="zan-cell__bd">单行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view class="zan-cell__text">单行列表</view>
        <view class="zan-cell__desc">附加描述</view>
      </view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">单行列表</view>
      <view class="zan-cell__ft"></view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--switch">
      <view class="zan-cell__bd">开关</view>
      <view class="zan-cell__ft">
        <zanSwitch :checked.sync="checked" componentId="zanSwitch"> </zanSwitch>
      </view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">单行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
    </view>
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
    </view>
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
    <view class="zan-cell">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft"></view>
    </view>
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft"></view>
    </view>
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft"></view>
    </view>
  </view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
    <view class="zan-cell zan-cell--access">
      <view class="zan-cell__bd">多行列表</view>
      <view class="zan-cell__ft">详细信息</view>
    </view>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'
import zanSwitch from '../components/zan-switch'

export default class Cell extends wepy.page {
  config = {
    navigationBarTitleText: 'Cell 单元格'
  }

  components = {
    zanSwitch
  }
  data = {
    checked: false
  }
  events = {
    zanSwitchChange(event) {
      let { checked } = event.source
      this.checked = !checked
      this.$apply()
    }
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/dashboard.wpy
================================================
<style lang='css'>
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';

.logo {
  display: block;
  margin: 40px auto;
  width: 92px;
  height: 82px;
}
</style>
<template>
  <view class="container">

    <image class="logo" src="https://img.yzcdn.cn/public_files/2017/02/06/ee0ebced79a80457d77ce71c7d414c74.png" />

    <block wx:for="{{ list }}" wx:for-item="group" wx:key="title">
      <view class="zan-panel-title">{{ group.title }}</view>
      <view class="zan-panel">
        <navigator wx:for="{{ group.content }}" wx:key="name" class="zan-cell zan-cell--access" url="{{ item.path }}">
          <view class="zan-cell__bd">{{ item.name }}</view>
          <view class="zan-cell__ft"></view>
        </navigator>
      </view>
    </block>

  </view>
</template>

<script>
import wepy from 'wepy'

export default class Dashboard extends wepy.page {
  data = {
    list: {
      base: {
        title: '基础组件',
        content: [
          {
            name: 'Badge 徽章',
            path: '/example/badge'
          },
          {
            name: 'Button 按钮',
            path: '/example/btn'
          },
          {
            name: 'Capsule 胶囊',
            path: '/example/capsule'
          },
          {
            name: 'Card 卡片',
            path: '/example/card'
          },
          {
            name: 'Cell 单元格',
            path: '/example/cell'
          },
          {
            name: 'Helper 基础样式',
            path: '/example/helper'
          },
          {
            name: 'Icon 图标',
            path: '/example/icon'
          },
          {
            name: 'Layout 布局',
            path: '/example/layout'
          },
          {
            name: 'Loadmore 加载',
            path: '/example/loadmore'
          },
          {
            name: 'Noticebar 通告栏',
            path: '/example/noticebar'
          },
          {
            name: 'Panel 面板',
            path: '/example/panel'
          },
          {
            name: 'Popup 弹出层',
            path: '/example/popup'
          },
          {
            name: 'Select 选择',
            path: '/example/select'
          },
          {
            name: 'Stepper 计数器',
            path: '/example/stepper'
          },
          {
            name: 'Steps 步骤条',
            path: '/example/steps'
          },
          {
            name: 'Switch 开关',
            path: '/example/switch'
          },
          {
            name: 'Tab 标签',
            path: '/example/tab'
          },
          {
            name: 'Tag 标记',
            path: '/example/tag'
          }
        ]
      },
      form: {
        title: '表单',
        content: [
          {
            name: 'Field 输入框',
            path: '/example/field'
          }
        ]
      },
      action: {
        title: '操作反馈',
        content: [
          {
            name: 'Actionsheet 行动按钮',
            path: '/example/actionsheet'
          },
          {
            name: 'Dialog 弹出框',
            path: '/example/dialog'
          },
          {
            name: 'Toast 轻提示',
            path: '/example/toast'
          },
          {
            name: 'TopTips 顶部提示',
            path: '/example/toptips'
          }
        ]
      }
    }
  }

  methods = {}

  onLoad() {
    wepy.getSystemInfo().then(data => {
      if (data.SDKVersion < '1.4.0') {
        wepy.showModal({ content: `SDKVersion最低要求1.4.0,当前版本${data.SDKVersion}`, title: '微信版本过低' })
      }
    })
  }
}
</script>


================================================
FILE: src/example/dialog.wpy
================================================
<style lang="css">
@import '/zanui/btn.wxss';

</style>

<template>
<block>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">DIALOG</view>

    <view class="zan-btns" style="margin-top: 30vh;">
      <button class="zan-btn" bindtap="toggleBaseDialog">
        基础 Dialog
      </button>
      <button class="zan-btn" bindtap="toggleWithoutTitleDialog">
        Dialog - 无标题
      </button>
      <button class="zan-btn" bindtap="toggleButtonDialog">
        Dialog - 自定义显示按钮
      </button>
      <button class="zan-btn" bindtap="toggleVerticalDialog">
        Dialog - 按钮纵向排布
      </button>
    </view>

  </view>

  <zanDialog/>
</block>
</template>

<script>
import wepy from 'wepy'
import zanDialog from '../components/zan-dialog'

export default class Dialog extends wepy.page {
  config = {}
  components = {
    zanDialog
  }
  data = {}
  methods = {
    toggleBaseDialog() {
      this.$invoke('zanDialog', 'showZanDialog', {
        title: '弹窗',
        content: '这是一个模态弹窗',
        showCancel: true
      })
        .then(() => {
          console.log('=== dialog ===', 'type: confirm')
        })
        .catch(() => {
          console.log('=== dialog ===', 'type: cancel')
        })
    },

    toggleWithoutTitleDialog() {
      this.$invoke('zanDialog', 'showZanDialog', {
        content: '这是一个模态弹窗'
      }).then(() => {
        console.log('=== dialog without title ===', 'type: confirm')
      })
    },

    toggleButtonDialog() {
      this.$invoke('zanDialog', 'showZanDialog', {
        title: '弹窗',
        content: '这是一个模态弹窗',
        buttons: [
          {
            text: '现金支付',
            color: 'red',
            type: 'cash'
          },
          {
            text: '微信支付',
            color: '#3CC51F',
            type: 'wechat'
          },
          {
            text: '取消',
            type: 'cancel'
          }
        ]
      }).then(({ type }) => {
        console.log('=== dialog with custom buttons ===', `type: ${type}`)
      })
    },

    toggleVerticalDialog() {
      this.$invoke('zanDialog', 'showZanDialog', {
        title: '弹窗',
        content: '这是一个模态弹窗',
        buttonsShowVertical: true,
        buttons: [
          {
            text: '现金支付',
            color: 'red',
            type: 'cash'
          },
          {
            text: '微信支付',
            color: '#3CC51F',
            type: 'wechat'
          },
          {
            text: '取消',
            type: 'cancel'
          }
        ]
      }).then(({ type }) => {
        console.log('=== dialog with vertical buttons ===', `type: ${type}`)
      })
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/field.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/btn.wxss';
.field__title--radius {
  padding-bottom: 10px;
}
</style>

<template>
<view class="container">
  <view class="doc-title zan-hairline--bottom">Field</view>

  <!-- Field 基础用法 -->
  <view class="zan-panel-title">基础用法</view>
  <view class="zan-panel">
    <zanField1 :options="base_name" :value="value" componentId="zanField1"></zanField1>
    <zanField2 :options="base_tel" :value="value" componentId="zanField2"></zanField2>
    <zanField3 :options="base_address" :value="value" componentId="zanField3"></zanField3>
  </view>

  <view class="zan-btns">
    <button
      class="zan-btn zan-btn--primary"
      bindtap="clearInput">清除输入</button>
  </view>

  <!-- 去除标题后的输入框样式 -->
  <view class="zan-panel-title">无标题输入框</view>
  <view class="zan-panel">
    <zanField4 :options="notitle" :value="textareaValue" componentId="zanField4"></zanField4>
  </view>

  <view class="zan-btns">
    <button
      class="zan-btn zan-btn--primary"
      bindtap="clearTextarea">清除输入</button>
  </view>

  <!-- 使用 Field 圆角样式 -->
  <view class="zan-panel-title field__title--radius">圆角输入框</view>
  <zanField5 :options="radius_totalPrice" componentId="zanField5"></zanField5>
  <zanField6 :options="radius_excludePrice" componentId="zanField6"></zanField6>
  <zanField7 :options="radius_notitle" componentId="zanField7"></zanField7>

  <!-- form 中使用 Field -->
  <view class="zan-panel-title">Form 表单中的field应用</view>
  <form bindsubmit="formSubmit" bindreset="formReset">
    <view class="zan-panel">
      <zanField8 :options="form_name" componentId="zanField8"></zanField8>
      <zanField9 :options="form_tel" componentId="zanField9"></zanField9>
      <view class="zan-btns">
        <button
          class="zan-btn zan-btn--primary"
          formType="submit">提交数据</button>
        <button
          class="zan-btn"
          formType="reset">重置数据</button>
      </view>
    </view>
  </form>

  <view class="zan-panel-title">自定义显示内容</view>
  <view class="zan-panel">
    <view class="zan-cell zan-field">
      <view class="zan-cell__hd zan-field__title">选择区域</view>
      <picker
        mode="selector"
        class="zan-field__input zan-cell__bd"
        range="{{ area }}"
        value="{{ areaIndex }}"
        bindchange="onAreaChange"
      >
        {{ area[areaIndex] }}
      </picker>
    </view>

    <view class="zan-cell zan-field">
      <view class="zan-cell__hd zan-field__title">验证码</view>
      <input
        type="text"
        placeholder="请输入短信验证码"
        class="zan-field__input zan-cell__bd"/>
      <view class="zan-cell__ft">
        <button class="zan-btn zan-btn--mini zan-btn--primary">获取验证码</button>
      </view>
    </view>
  </view>
</view>
</template>

<script>
import wepy from 'wepy'
import zanField from '../components/zan-field'

export default class field extends wepy.page {
  config = {
    navigationBarTitleText: 'Field 输入框'
  }
  components = {
    zanField1: zanField,
    zanField2: zanField,
    zanField3: zanField,
    zanField4: zanField,
    zanField5: zanField,
    zanField6: zanField,
    zanField7: zanField,
    zanField8: zanField,
    zanField9: zanField,
  }
  data = {
    // 基础类型输入框配置
    base_name: {
      title: '收货人',
      placeholder: '名字'
    },
    base_tel: {
      error: true,
      title: '联系电话',
      inputType: 'number',
      placeholder: '请输入手机号'
    },
    base_address: {
      title: '详细地址',
      type: 'textarea',
      placeholder: '请输入详细地址'
    },
    // 无标题输入框
    notitle: {
      placeholder: '请输入收货人姓名',
      componentId: 'textarea:test'
    },
    // 圆角输入框
    radius_totalPrice: {
      right: true,
      mode: 'wrapped',
      title: '消费总额',
      inputType: 'number',
      placeholder: '询问收银员后输入'
    },
    radius_excludePrice: {
      right: true,
      error: true,
      mode: 'wrapped',
      title: '不参与优惠金额',
      inputType: 'number',
      placeholder: '询问收银员后输入'
    },
    radius_notitle: {
      mode: 'wrapped',
      inputType: 'number',
      placeholder: '请输入消费金额'
    },
    // Form 中使用输入框
    form_name: {
      name: 'name',
      placeholder: '请输入收货人姓名',
      componentId: 'form:test:name'
    },
    form_tel: {
      name: 'tel',
      inputType: 'tel',
      placeholder: '请输入收货人手机号码',
      componentId: 'form:test:tel'
    },
    value: 'test',
    textareaValue: 'test textarea',
    area: [
      '省份',
      '北京市',
      '天津市',
      '河北省',
      '山西省',
      '内蒙古自治区',
      '辽宁省',
      '吉林省',
      '黑龙江省',
      '上海市',
      '江苏省',
      '浙江省',
      '安徽省',
      '福建省',
      '江西省',
      '山东省',
      '河南省',
      '湖北省',
      '湖南省',
      '广东省',
      '广西壮族自治区',
      '海南省',
      '重庆市',
      '四川省',
      '贵州省',
      '云南省',
      '西藏自治区',
      '陕西省',
      '甘肃省',
      '青海省',
      '宁夏回族自治区',
      '新疆维吾尔自治区',
      '台湾省',
      '香港特别行政区',
      '澳门特别行政区'
    ],
    areaIndex: 0
  }
  methods = {
    onAreaChange(e) {
      this.areaIndex = e.detail.value
      this.$apply()
    },

    clearInput() {
      this.$invoke('zanField1', 'clear')
      this.$invoke('zanField2', 'clear')
      this.$invoke('zanField3', 'clear')
    },

    clearTextarea() {
      this.$invoke('zanField4', 'clear')
    },

    formSubmit(event) {
      console.log('[zan:field:submit]', event.detail.value)
    },

    formReset(event) {
      console.log('[zan:field:reset]', event)
    }
  }
  events = {
    zanFieldChange(e) {
      const { componentId, detail } = e

      console.log('[zan:field:change]', componentId, detail)
    },

    zanFieldFocus(e) {
      const { componentId, detail } = e

      console.log('[zan:field:focus]', componentId, detail)
    },

    zanFieldBlur(e) {
      const { componentId, detail } = e

      console.log('[zan:field:blur]', componentId, detail)
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/helper.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';
@import '/zanui/color.wxss';
</style>

<template>
<view class="container">

  <view class="zan-panel">
    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view class="zan-pull-right">zan-pull-right: 往右靠</view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view class="zan-text-deleted">zan-text-deleted:被删除的效果</view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view>
          <view class="zan-font-12">zan-font-12:字号12</view>
          <view class="zan-font-12 zan-font-bold">zan-font-bold:再来个加粗</view>
        </view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view>
          <view class="zan-font-16">zan-font-16:字号16</view>
          <view class="zan-font-16 zan-font-bold">zan-font-bold:再来个加粗</view>
        </view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view class="">
          <view>字体颜色</view>
          <view class="zan-c-red">zan-c-red: 红色</view>
          <view class="zan-c-gray">zan-c-gray: 灰色</view>
          <view class="zan-c-gray-dark">zan-c-gray-dark: 再灰一点点</view>
          <view class="zan-c-gray-darker">zan-c-gray-darker: 更深的灰色</view>
          <view class="zan-c-black">zan-c-black: 黑色</view>
          <view class="zan-c-blue">zan-c-blue: 蓝色</view>
          <view class="zan-c-green">zan-c-green: 绿色</view>
        </view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view>zan-arrow:箭头</view>
        <view class="zan-arrow"></view>
      </view>
    </view>

    <view class="zan-cell">
      <view class="zan-cell__bd">
        <view class="zan-ellipsis" style="width: 300px;">
          zan-ellipsis:单行点点点
          ->我是占位的字符我是占位的字符我是占位的字符我是占位的字符我是占位的字符我是占位的字符
        </view>
      </view>
    </view>

    <view class="zan-cell zan-cell--last-child">
      <view class="zan-cell__bd">
        <view class="zan-ellipsis--l2">
          zan-ellipsis--l2:单行点点点
          ->我是占位的字符我是占位的字符我是占位的字符我是占位的字符我是占位的字符我是占位的字符
        </view>
      </view>
    </view>

  </view>

</view>
</template>

<script>
import wepy from 'wepy'
export default class Helper extends wepy.page {
  config = {
    navigationBarTitleText: 'Helper 基础样式'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/icon.wpy
================================================
<style lang="css">
@import '/zanui/icon.wxss';

.icon-wrap {
  width: 33.33333%;
  height: 100px;
  float: left;
  text-align: center;
}
.icon-classname {
  color: #999;
  font-size: 10px;
}
.zan-icon {
  font-size: 24px;
  margin: 20px;
}
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">ICON</view>

  <view class="zan-panel">
    <view wx:for="{{ icons }}" wx:for-item="icon" class="icon-wrap">
      <view class="zan-icon zan-icon-{{ icon }}"  style="color: #ff4343;"></view>
      <view class="icon-classname">zan-icon-{{ icon }}</view>
    </view>
  </view>
</view>
</template>

<script>
import wepy from 'wepy'

export default class Icon extends wepy.page {
  config = {
    navigationBarTitleText: 'Icon 图标'
  }
  components = {}
  data = {
    icons: [
      'close',
      'location',
      'clock',
      'gold-coin',
      'chat',
      'exchange',
      'upgrade',
      'edit',
      'contact',
      'passed',
      'points',
      'delete',
      'records',
      'logistics',
      'check',
      'checked',
      'gift',
      'like-o',
      'like',
      'qr',
      'qr-invalid',
      'shop',
      'photograph',
      'add',
      'add2',
      'add-o',
      'photo',
      'cart',
      'arrow',
      'search',
      'clear',
      'success',
      'fail',
      'wechat',
      'alipay',
      'password-view',
      'wap-nav',
      'password-not-view',
      'wap-home',
      'ecard-pay',
      'balance-pay',
      'peer-pay',
      'credit-pay',
      'debit-pay',
      'other-pay',
      'shopping-cart',
      'browsing-history',
      'goods-collect',
      'shop-collect',
      'receive-gift',
      'send-gift',
      'setting',
      'coupon',
      'free-postage',
      'discount',
      'birthday-privilege',
      'member-day-privilege',
      'balance-details',
      'cash-back-record',
      'points-mall',
      'exchange-record',
      'pending-payment',
      'pending-orders',
      'pending-deliver',
      'pending-evaluate',
      'cash-on-deliver',
      'gift-card-pay',
      'underway',
      'point-gift',
      'after-sale',
      'edit-data',
      'question',
      'description',
      'card',
      'gift-card',
      'completed',
      'value-card',
      'certificate',
      'tosend',
      'sign',
      'home',
      'phone',
      'play',
      'pause',
      'stop',
      'hot',
      'new',
      'new-arrival',
      'hot-sale'
    ]
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/label.wpy
================================================
<style lang="less">

</style>

<template>
  <view class="container">

    <view class="doc-title">LABEL</view>

    <view class="zan-panel">
      <view class="zan-cell zan-cell--last-child">
        <view class="zan-label">蓝色</view>
        <view class="zan-label zan-label--primary">红色</view>
        <view class="zan-label zan-label--disabled">黑色</view>
      </view>
    </view>
    <view class="zan-panel">
      <view class="zan-cell zan-cell--last-child">
        <view class="zan-label zan-label--primary zan-label--small">会员折扣</view>
        <view class="zan-label zan-label--primary zan-label--small">返现</view>
      </view>
    </view>

    <view class="zan-panel">
      <view class="zan-cell zan-cell--last-child">
        <view class="zan-label zan-label--primary zan-label--small zan-label--plain">会员折扣</view>
        <view class="zan-label zan-label--primary zan-label--small zan-label--plain">返现</view>
      </view>
    </view>
  </view>
</template>

<script>
import wepy from 'wepy'

export default class Label extends wepy.page {
  config = {}
  components = {}
  data = {}
  events = {}
  methods = {}
  onLoad() { }
}
</script>


================================================
FILE: src/example/layout.wpy
================================================
<style lang='css'>
@import '/zanui/panel.wxss';
@import '/zanui/col.wxss';
@import '/zanui/row.wxss';

.zan-col {
  line-height: 30px;
  text-align: center;
  background-color: #39a9ed;
  font-size: 12px;
  color: #fff;
}

.zan-col:nth-child(even) {
  background-color: #66c6f2;
}
</style>
<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">LAYOUT</view>

  <view class="zan-panel-title">基础用法</view>
  <view class="doc-description">Layout 组件提供了24列栅格,添加 zan-col-x 可以设置元素所占宽度</view>
  <view class="zan-panel">
    <view class="zan-row">
      <view class="zan-col zan-col-8">
        span: 8
      </view>
      <view class="zan-col zan-col-8">
        span: 8
      </view>
      <view class="zan-col zan-col-8">
        span: 8
      </view>
    </view>
  </view>

  <view class="zan-panel-title">offset</view>
  <view class="doc-description">添加 zan-col-offset-x 类可以设置列的偏移宽度,计算方式与 span 相同</view>
  <view class="zan-panel">
    <view class="zan-row">
      <view class="zan-col zan-col-4">span: 4</view>
      <view class="zan-col zan-col-10 zan-col-offset-4">offset: 4, span: 10</view>
    </view>
    <view class="zan-row">
      <view class="zan-col zan-col-12 zan-col-offset-12">offset: 12, span: 12</view>
    </view>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'

export default class Layout extends wepy.page {
  config = {
    navigationBarTitleText: 'Layout 布局'
  }
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/loadmore.wpy
================================================
<style lang="css">

</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">LOADMORE</view>

  <zanLoadmore1 :loading="_true" > </zanLoadmore1>
  <zanLoadmore2 :nodata="_true" nodata_str="暂无数据 Wepy"></zanLoadmore2>
  <zanLoadmore3 :nomore="_true" ></zanLoadmore3>
</view>
</template>

<script>
import wepy from 'wepy'
import zanLoadmore from '../components/zan-loadmore'

export default class Loadmore extends wepy.page {
  config = {
    navigationBarTitleText: 'Loadmore 加载'
  }
  components = {
    zanLoadmore1: zanLoadmore,
    zanLoadmore2: zanLoadmore,
    zanLoadmore3: zanLoadmore
  }
  data = {
    _true: true,
    _false: false
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/noticebar.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';

</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">NOTICEBAR</view>

  <view class="zan-panel-title">滚动通告栏</view>
  <view class="zan-panel">
    <zanNoticebar1 :text="longText" componentId="movable" ></zanNoticebar1>
  </view>

  <view class="zan-panel-title">静止通告栏1</view>
  <view class="zan-panel">
    <zanNoticebar2 :text="shortText" componentId="static1" ></zanNoticebar2>
  </view>

  <view class="zan-panel-title">静止通告栏2(3秒后滚动)</view>
  <view class="zan-panel">
    <zanNoticebar3 :text="longText" componentId="static2" ></zanNoticebar3>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'
import zanNoticebar from '../components/zan-noticebar'

export default class Noticebar extends wepy.page {
  config = {
    navigationBarTitleText: 'Noticebar 通告栏'
  }
  components = {
    zanNoticebar1: zanNoticebar,
    zanNoticebar2: zanNoticebar,
    zanNoticebar3: zanNoticebar
  }
  data = {
    longText: '足协杯战线连续第2年上演广州德比战,上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。',
    shortText: '足协杯战线连续第2年上演广州德比战'
  }
  methods = {}
  onLoad() {}
  onReady() {
    // 滚动通告栏需要initScroll
    this.$invoke('zanNoticebar1', 'initZanNoticeBarScroll')
    // initScroll的通告栏如果宽度足够显示内容将保持静止
    this.$invoke('zanNoticebar2', 'initZanNoticeBarScroll')
    // 不进行initScroll的通告栏也将保持静止
    setTimeout(() => {
      this.$invoke('zanNoticebar3', 'initZanNoticeBarScroll')
    }, 3000)
  }
}
</script>


================================================
FILE: src/example/panel.wpy
================================================
<style lang='css'>
@import '/zanui/panel.wxss';
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">PANEL</view>

  <view class="zan-panel-title">标题</view>
  <view class="zan-panel">
    <view style="padding: 15px;">内容</view>
  </view>

  <view class="zan-panel">
    <view style="padding: 15px;">内容</view>
  </view>

  <view class="zan-panel zan-panel--without-border">
    <view style="padding: 15px;">无边框的panel</view>
  </view>

  <view class="zan-panel">
    <view style="padding: 15px;">内容</view>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'

export default class Panel extends wepy.page {
  config = {
    navigationBarTitleText: 'Panel 面板'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/popup.wpy
================================================
<style lang="css">
@import '/zanui/btn.wxss';
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">POPUP</view>

  <view class="zan-btns" style="margin-top: 30vh;">
    <button class="zan-btn" bindtap="togglePopup">
      弹出popup
    </button>
    <button class="zan-btn" bindtap="toggleTopPopup">
      从顶部弹出popup
    </button>
    <button class="zan-btn" bindtap="toggleBottomPopup">
      从底部弹出popup
    </button>
    <button class="zan-btn" bindtap="toggleLeftPopup">
      从左边弹出popup
    </button>
    <button class="zan-btn" bindtap="toggleRightPopup">
      从右边弹出popup
    </button>
  </view>

  <zanPopup1>
    <view class="zan-btns">
      <button class="zan-btn" @tap="togglePopup">
        关闭 popup
      </button>
    </view>
  </zanPopup1>

  <zanPopup2 direction="left">
    <view class="zan-btns">
      <button class="zan-btn" @tap="toggleLeftPopup">
        关闭 popup
      </button>
    </view>
  </zanPopup2>


  <zanPopup3 direction="right">
    <view class="zan-btns">
      <button class="zan-btn" @tap="toggleRightPopup">
        关闭 popup
      </button>
    </view>
  </zanPopup3>

  <zanPopup4 direction="top">
    内容
  </zanPopup4>

  <zanPopup5 direction="bottom">
    <view class="zan-btns">
      <button class="zan-btn" @tap="toggleBottomPopup">
        关闭 popup
      </button>
    </view>
  </zanPopup5>

</view>
</template>

<script>
import wepy from 'wepy'
import zanPopup from '../components/zan-popup'

export default class Popup extends wepy.page {
  config = {
    navigationBarTitleText: 'Popup 弹出层'
  }
  components = {
    zanPopup1: zanPopup,
    zanPopup2: zanPopup,
    zanPopup3: zanPopup,
    zanPopup4: zanPopup,
    zanPopup5: zanPopup
  }
  data = {}
  methods = {
    togglePopup() {
      this.$invoke('zanPopup1', 'togglePopup')
    },

    toggleLeftPopup() {
      this.$invoke('zanPopup2', 'togglePopup')
    },

    toggleRightPopup() {
      this.$invoke('zanPopup3', 'togglePopup')
    },

    toggleTopPopup() {
      this.$invoke('zanPopup4', 'togglePopup')
    },

    toggleBottomPopup() {
      this.$invoke('zanPopup5', 'togglePopup')
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/select.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/btn.wxss';
</style>

<template>
<block>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">SELECT</view>

    <view class="zan-panel-title">基础用法</view>
    <view class="zan-panel">
      <view>
        <zanSelect1 :items="items" :checkedValue.sync="checked_base" componentId="base" ></zanSelect1>
      </view>
    </view>

    <view class="zan-panel-title">自定义高亮颜色</view>
    <view class="zan-panel">
      <view>
        <zanSelect2 :items="items" :checkedValue.sync="checked_color" :activeColor="activeColor" componentId="color" ></zanSelect2>
      </view>
    </view>

    <view class="zan-panel-title">Form 表单中的select应用</view>
    <form bindsubmit="formSubmit">
      <view class="zan-panel">
        <view>
          <zanSelect3 :items="items" :checkedValue.sync="checked_form" name="formtest" componentId="form"></zanSelect3>
        </view>
      </view>

      <view class="zan-btns">
        <button
          class="zan-btn zan-btn--primary"
          formType="submit">提交数据</button>
      </view>
    </form>
  </view>
  <zanToptips />
</block>
</template>

<script>
import wepy from 'wepy'
import zanSelect from '../components/zan-select'
import zanToptips from '../components/zan-toptips'

export default class Select extends wepy.page {
  config = {
    navigationBarTitleText: 'Select 选择'
  }
  components = {
    zanSelect1: zanSelect,
    zanSelect2: zanSelect,
    zanSelect3: zanSelect,
    zanToptips
  }
  data = {
    items: [
      {
        padding: 0,
        value: '1',
        name: '选项一'
      },
      {
        padding: 0,
        value: '2',
        name: '选项二'
      }
    ],

    checked_base: -1,
    checked_color: -1,
    checked_form: -1,

    activeColor: '#4b0'
  }
  events = {
    zanSelectChange(value, event) {
      let { componentId } = event.source
      this[`checked_${componentId}`] = value
      this.$apply()
    }
  }
  methods = {
    formSubmit(event) {
      console.log('[zan:field:submit]', event.detail.value)
      this.$invoke('zanToptips', 'showZanTopTips', { content: `选中的值为${event.detail.value.formtest}` })
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/stepper.wpy
================================================
<style lang="less">
.zan-panel {
  padding: 10px;
}

.zan-switch {
  margin-right: 8px;
}
</style>

<template>
  <view class="container">

    <view class="doc-title">QUANTITY</view>

    <view style="padding: 40px 15px">
      <zanStepper1 :stepper.sync="stepper1" :min="min1" :max="max1" componentId="stepper1"> </zanStepper1>
    </view>

    <!-- 当最大值等于最小值时,组件不可用 -->
    <view style="padding: 40px 15px ">
      <zanStepper2 :stepper.sync="stepper2" :min="min2" :max="max2" componentId="stepper2"> </zanStepper2>
    </view>

    <!-- small size -->
    <view style="padding: 40px 15px ">
      <zanStepper3 :stepper.sync="stepper3" :min="min3" :max="max3" componentId="stepper3" size="small"> </zanStepper3>
    </view>
  </view>
</template>

<script>
import wepy from 'wepy'
import zanStepper from '../components/zan-stepper'

export default class Stepper extends wepy.page {
  config = {
    navigationBarTitleText: 'Stepper 计数器'
  }
  components = {
    zanStepper1: zanStepper,
    zanStepper2: zanStepper,
    zanStepper3: zanStepper
  }
  data = {
    stepper1: 10,
    min1: 1,
    max1: 20,
    stepper2: 1,
    min2: 1,
    max2: 1,
    stepper3: 10,
    min3: 1,
    max3: 20
  }
  events = {
    zanStepperChange({ componentId, stepper }, event) {
      // console.log(componentId, stepper, event)
      this[componentId] = stepper
      this.$apply()
    }
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/steps.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';
.my-class {
  padding: 10px;
}
.my-class .zan-steps__step--done {
  color: #f44;
}
</style>

<template>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">STEPS</view>

    <view class="zan-panel">
      <view class="zan-cell">
        <view class="zan-cell__bd">
          <zanSteps1 type="horizon" :steps="steps"></zanSteps1>
        </view>
      </view>

      <view class="zan-cell">
        <view class="zan-cell__bd">
          <zanSteps2 type="horizon" :steps="steps2"></zanSteps2>
        </view>
      </view>

      <view class="zan-cell zan-cell--last-child">
        <view class="zan-cell__bd">
          <zanSteps3 type="horizon" :steps="steps3"></zanSteps3>
        </view>
      </view>
    </view>

    <view class="zan-panel-title">有描述的steps</view>
    <view class="zan-panel">
      <view class="zan-cell">
        <view class="zan-cell__bd">
          <zanSteps4 type="horizon" :hasDesc="_true" :steps="steps"></zanSteps4>
        </view>
      </view>

      <view class="zan-cell">
        <view class="zan-cell__bd">
          <zanSteps5 type="horizon" :hasDesc="_true" :steps="steps2"></zanSteps5>
        </view>
      </view>

      <view class="zan-cell zan-cell--last-child">
        <view class="zan-cell__bd">
          <zanSteps6 type="horizon" :hasDesc="_true" :steps="steps3"></zanSteps6>
        </view>
      </view>
    </view>

    <view class="zan-panel-title">垂直方向的steps</view>
    <view class="zan-panel">
      <view class="zan-cell zan-cell">
        <view class="zan-cell__bd">
          <zanSteps7 type="vertical" :hasDesc="_true" :steps="steps"></zanSteps7>
        </view>
      </view>

      <view class="zan-cell zan-cell--last-child">
        <view class="zan-cell__bd">
          <zanSteps8 type="vertical" :steps="steps"></zanSteps8>
        </view>
      </view>
    </view>

    <view class="zan-panel-title">可自定义class</view>
    <view class="zan-panel">
      <view class="zan-cell__bd">
        <zanSteps9 type="vertical" :steps="steps" className='my-class'></zanSteps9>
      </view>
    </view>

  </view>
</template>

<script>
import wepy from 'wepy'
import zanSteps from '../components/zan-steps'

export default class Steps extends wepy.page {
  config = {
    navigationBarTitleText: 'Steps 步骤条'
  }
  components = {
    zanSteps1: zanSteps,
    zanSteps2: zanSteps,
    zanSteps3: zanSteps,
    zanSteps4: zanSteps,
    zanSteps5: zanSteps,
    zanSteps6: zanSteps,
    zanSteps7: zanSteps,
    zanSteps8: zanSteps,
    zanSteps9: zanSteps
  }
  data = {
    _true: true,
    steps: [
      {
        current: true,
        done: true,
        text: '步骤一',
        desc: '10.01'
      },
      {
        done: false,
        current: false,
        text: '步骤二',
        desc: '10.02'
      },
      {
        done: false,
        current: false,
        text: '步骤三'
      }
    ],
    steps2: [
      {
        current: false,
        done: true,
        text: '步骤一',
        desc: '10.01'
      },
      {
        done: true,
        current: true,
        text: '步骤二',
        desc: '10.02'
      },
      {
        done: false,
        current: false,
        text: '步骤三',
        desc: '10.03'
      }
    ],
    steps3: [
      {
        current: false,
        done: true,
        text: '步骤一',
        desc: '10.01'
      },
      {
        done: true,
        current: false,
        text: '步骤二',
        desc: '10.02'
      },
      {
        done: true,
        current: true,
        text: '步骤三',
        desc: '10.03'
      }
    ]
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/switch.wpy
================================================
<style lang="css">
@import '/zanui/panel.wxss';
@import '/zanui/card.wxss';

.zan-panel {
  padding: 10px;
}

.zan-switch {
  margin-right: 8px;
}
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">SWITCH</view>

  <view class="zan-panel-title">同步开关</view>
  <view class="zan-panel">
    <syncSwitch :checked.sync="sync_checked" componentId="sync"> </syncSwitch>
  </view>

  <view class="zan-panel-title">异步开关</view>
  <view class="zan-panel">
    <asyncSwitch :checked.sync="async_checked" :loading.sync="async_loading" componentId="async"> </asyncSwitch>
  </view>

  <view class="zan-panel-title">开关不可用</view>
  <view class="zan-panel">
    <switch3 :checked="_false" :disabled="_true" componentId='switch3'> </switch3>
    <switch4 :checked="_true" :disabled="_true" componentId='switch4'> </switch4>
  </view>

</view>
</template>

<script>
import wepy from 'wepy'
import zanSwitch from '../components/zan-switch'

export default class Switch extends wepy.page {
  config = {
    navigationBarTitleText: 'Switch 开关'
  }
  components = {
    syncSwitch: zanSwitch,
    asyncSwitch: zanSwitch,
    switch3: zanSwitch,
    switch4: zanSwitch
  }
  data = {
    sync_checked: false,
    async_checked: true,
    async_loading: false,
    _true: true,
    _false: false
  }
  events = {
    zanSwitchChange(event) {
      console.log(event)
      let { componentId, checked } = event.source
      if (componentId === 'sync') {
        // 同步开关
        this.sync_checked = !checked
        this.$apply()
      } else if (componentId === 'async') {
        // 异步开关
        this.async_loading = true
        setTimeout(() => {
          this.async_loading = false
          this.async_checked = !checked
          this.$apply()
        }, 500)
      }
    }
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/tab.wpy
================================================
<style lang="css">

</style>

<template>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">TAB</view>

    <view style="margin: 20px 0">
      <zanTab1 :options="tab1" componentId="tab1"></zanTab1>
    </view>
    <view style="margin: 20px 0">
      <zanTab2 :options="tab2" componentId="tab2"></zanTab2>
    </view>
    <view style="margin: 20px 0">
      <zanTab3 :options="tab3" componentId="tab3"></zanTab3>
    </view>
  </view>
</template>

<script>
import wepy from 'wepy'
import zanTab from '../components/zan-tab'

export default class Tab extends wepy.page {
  config = {
    navigationBarTitleText: 'Tab 标签'
  }
  components = {
    zanTab1: zanTab,
    zanTab2: zanTab,
    zanTab3: zanTab
  }
  data = {
    tab1: {
      list: [
        {
          id: 'all',
          title: '全部'
        },
        {
          id: 'topay',
          title: '待付款'
        },
        {
          id: 'tosend',
          title: '待发货'
        },
        {
          id: 'send',
          title: '待收货'
        },
        {
          id: 'sign',
          title: '已完成'
        }
      ],
      selectedId: 'all',
      scroll: false
    },
    tab2: {
      list: [
        {
          id: '1',
          title: '最新商品1'
        },
        {
          id: '2',
          title: '最新商品2'
        },
        {
          id: '3',
          title: '最新商品3'
        },
        {
          id: '4',
          title: '最新商品4'
        },
        {
          id: '5',
          title: '最新商品5'
        },
        {
          id: '6',
          title: '最新商品6'
        }
      ],
      selectedId: '1',
      scroll: true,
      height: 45
    },
    tab3: {
      list: [
        {
          id: '1',
          title: '商品1'
        },
        {
          id: '2',
          title: '商品2'
        },
        {
          id: '3',
          title: '商品3'
        },
        {
          id: '4',
          title: '商品4'
        },
        {
          id: '5',
          title: '商品5'
        },
        {
          id: '6',
          title: '商品6'
        }
      ],
      selectedId: '1',
      scroll: true,
      height: 45
    }
  }
  events = {
    zanTabChange({ selectedId }, event) {
      let { componentId } = event.source
      console.log('Page Tab receive selectedId:', componentId, selectedId)
    }
  }
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/tag.wpy
================================================
<style lang='css'>
@import '/zanui/panel.wxss';
@import '/zanui/cell.wxss';
@import '/zanui/tag.wxss';
.zan-tag + .zan-tag {
  margin-left: 10px;
}
</style>

<template>
<view class="container">

  <view class="doc-title zan-hairline--bottom">Tag</view>

  <view class="zan-panel">
    <view class="zan-cell zan-cell--last-child">
      <view class="zan-tag">灰色</view>
      <view class="zan-tag zan-tag--danger">红色</view>
      <view class="zan-tag zan-tag--disabled">不可用</view>
    </view>
  </view>
  <view class="zan-panel">
    <view class="zan-cell zan-cell--last-child">
      <view class="zan-tag zan-tag--danger">会员折扣</view>
      <view class="zan-tag zan-tag--warn">返现</view>
      <view class="zan-tag zan-tag--primary">返现</view>
      <view class="zan-tag zan-tag--primary zan-tag--disabled">不可用</view>
    </view>
  </view>

    <view class="zan-panel">
    <view class="zan-cell zan-cell--last-child">
      <view class="zan-tag zan-tag--plain">灰色</view>
      <view class="zan-tag zan-tag--danger zan-tag--plain">会员折扣</view>
      <view class="zan-tag zan-tag--warn zan-tag--plain">返现</view>
      <view class="zan-tag zan-tag--primary zan-tag--plain">返现</view>
      <view class="zan-tag zan-tag--primary zan-tag--plain zan-tag--disabled">返现不可用</view>
    </view>
  </view>
</view>
</template>

<script>
import wepy from 'wepy'

export default class Tag extends wepy.page {
  config = {
    navigationBarTitleText: 'Tag 标记'
  }
  components = {}
  data = {}
  methods = {}
  onLoad() {}
}
</script>


================================================
FILE: src/example/toast.wpy
================================================
<style lang="css">

</style>

<template>
<block>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">TOAST</view>

    <view class="zan-btns" style="margin-top: 30vh;">
      <button class="zan-btn" @tap="showToast">
        显示toast
      </button>
    </view>
  </view>

  <zanToast></zanToast>
</block>
</template>

<script>
import wepy from 'wepy'
import zanToast from '../components/zan-toast'

export default class Toast extends wepy.page {
  config = {
    navigationBarTitleText: 'Toast 轻提示'
  }
  components = {
    zanToast
  }
  data = {}
  methods = {
    showToast() {
      this.$invoke('zanToast', 'showZanToast', { title: 'Toast的内容 Wepy', timeout: 2000 })
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/example/toptips.wpy
================================================
<style lang="less">

</style>

<template>
<block>
  <view class="container">

    <view class="doc-title zan-hairline--bottom">TOPTIPS</view>

    <view class="zan-btns" style="margin-top: 30vh;">
      <button class="zan-btn" bindtap="showTopTips">
        显示toptips
      </button>
    </view>
  </view>
  <zanToptips/>
</block>
</template>

<script>
import wepy from 'wepy'
import zanToptips from '../components/zan-toptips'

export default class Toptips extends wepy.page {
  config = {
    navigationBarTitleText: 'Toptips 顶部提示'
  }

  components = {
    zanToptips
  }
  data = {}
  methods = {
    showTopTips() {
      this.$invoke('zanToptips', 'showZanTopTips', { content: 'toptips的内容 Wepy', options: 1000 })
    }
  }
  onLoad() {}
}
</script>


================================================
FILE: src/zanui/badge.scss
================================================
.zan-badge {
  position: relative;
}
.zan-badge__count {
  position: absolute;
  top: -16px;
  right: 0px;
  height: 1.6em;
  min-width: 1.6em;
  line-height: 1.6;
  padding: 0 0.4em;
  font-size: 20px;
  border-radius: 0.8em;
  background: #ff4444;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  transform: translateX(50%) scale(0.5);
  transform-origin: center;
  z-index: 10;
  box-shadow: 0 0 0 2px #fff;
  box-sizing: border-box;
}


================================================
FILE: src/zanui/btn.scss
================================================
@import "common";

.zan-btn {
  position: relative;
  color: #333;
  background-color: #fff;
  margin-bottom: 10px;
  padding-left: 15px;
  padding-right: 15px;
  border-radius: 2px;
  font-size: 16px;
  line-height: 45px;
  height: 45px;
  box-sizing: border-box;
  text-decoration: none;
  text-align: center;
  vertical-align: middle;
}

.zan-btn::after {
  @include hairline;
  border-width: 1px;
  border-radius: 4px;
}

.zan-btns {
  margin: 15px;
}

/* type */
.zan-btn--primary {
  color: #fff;
  background-color: #4b0;

  &::after {
    border-color: #0a0;
  }
}

.zan-btn--warn {
  color: #fff;
  background-color: #f85;

  &::after {
    border-color: #f85;
  }
}

.zan-btn--danger {
  color: #fff;
  background-color: #f44;

  &::after {
    border-color: #e33;
  }
}

/* size */
.zan-btn--small {
  display: inline-block;
  height: 30px;
  line-height: 30px;
  font-size: 12px;
  margin-right: 5px;
  margin-bottom: 0;
}
.zan-btn--mini {
  display: inline-block;
  line-height: 21px;
  height: 22px;
  font-size: 10px;
  margin-right: 5px;
  margin-bottom: 0;
  padding-left: 5px;
  padding-right: 5px;
}
.zan-btn--large {
  border-radius: 0;
  margin-bottom: 0;
  border: none;
  line-height: 50px;
  height: 50px;
}

/* plain */
.zan-btn--plain.zan-btn {
  background-color: transparent;
}
.zan-btn--plain.zan-btn--primary {
  color: #06BF04;
}
.zan-btn--plain.zan-btn--warn {
  color: #FF6600;
}
.zan-btn--plain.zan-btn--danger {
  color: #FF4444;
}

/* 重写button组件的button-hover样式 */
.button-hover {
  opacity: 0.9;
}

/* loading */
.zan-btn--loading {
  color: transparent;
  opacity: 1;
}
.zan-btn--loading::before {
  position: absolute;
  left: 50%;
  top: 50%;
  content: ' ';
  width: 16px;
  height: 16px;
  margin-left: -8px;
  margin-top: -8px;
  border: 3px solid #e5e5e5;
  border-color: #666 #e5e5e5 #e5e5e5 #e5e5e5;
  border-radius: 8px;
  box-sizing: border-box;
  animation: btn-spin 0.6s linear;
  animation-iteration-count: infinite;
}
.zan-btn--primary.zan-btn--loading::before,
.zan-btn--warn.zan-btn--loading::before,
.zan-btn--danger.zan-btn--loading::before {
  border-color: #fff rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1);
}

@keyframes btn-spin {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

/* disabled */
.zan-btn.zan-btn--disabled {
  /* 防止样式被 button[disabled] 的规则覆盖,所以使用了important */
  color: #999 ! important;
  background: #f8f8f8 ! important;
  border-color: #e5e5e5 ! important;
  cursor: not-allowed ! important;
  opacity: 1 ! important;

  &::after {
    border-color: #e5e5e5 ! important;
  }
}

/* :last-child */
.zan-btn--last-child,
.zan-btn:last-child {
  margin-bottom: 0;
  margin-right: 0;
}



================================================
FILE: src/zanui/card.scss
================================================
.zan-card {
  margin-left: 0px;
  width: auto;
  padding: 5px 15px;
  overflow: hidden;
  position: relative;
  font-size: 14px;
}

.zan-card__thumb {
  width: 90px;
  height: 90px;
  float: left;
  position: relative;
  margin-left: auto;
  margin-right: auto;
  overflow: hidden;
  background-size: cover;
}

.zan-card__img {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}

.zan-card__detail {
  margin-left: 100px;
  width: auto;
  position: relative;
}

.zan-card__detail-row {
  overflow: hidden;
  line-height: 20px;
  min-height: 20px;
  margin-bottom: 3px;
}

.zan-card__right-col {
  float: right;
}

.zan-card__left-col {
  margin-right: 80px;
}


================================================
FILE: src/zanui/cell.scss
================================================
@import "common";

.zan-cell {
  position: relative;
  padding: 12px 15px;
  display: flex;
  align-items: center;
  line-height: 1.4;
  font-size: 14px;
}

.zan-cell::after {
  @include hairline;
  border-bottom-width: 1px;
  left: 15px;
  right: 0;
}

.zan-cell__icon {
  margin-right: 5px;
}
.zan-cell__bd {
  flex: 1;
}
.zan-cell__text {
  line-height: 24px;
  font-size: 14px;
}
.zan-cell__desc {
  line-height: 1.2;
  font-size: 12px;
  color: #666;
}
.zan-cell__ft {
  position: relative;
  text-align: right;
  color: #666;
}
.zan-cell__no-pading{
  padding: 0;
}
.zan-cell__no-pading .zan-cell__bd_padding {
  padding: 12px 0 12px 15px;
}
.zan-cell__no-pading .zan-cell__bd_padding .zan-form__input{
  height: 26px;
}
.zan-cell__no-pading .zan-cell__ft_padding {
  padding: 12px 15px 12px 0;
}

.zan-cell--last-child::after,
.zan-cell:last-child::after {
  display: none;
}

.zan-cell--access .zan-cell__ft {
  padding-right: 13px;
}

.zan-cell--access .zan-cell__ft::after {
  position: absolute;
  top: 50%;
  right: 2px;
  content: " ";
  display: inline-block;
  height: 6px;
  width: 6px;
  border-width: 2px 2px 0 0;
  border-color: #c8c8c8;
  border-style: solid;
  transform: translateY(-50%) matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
}
.zan-cell--switch {
  padding-top: 6px;
  padding-bottom: 6px;
}


================================================
FILE: src/zanui/col.scss
================================================
.zan-col {
  float: left;
  box-sizing: border-box;
  width: 0;
}

@for $i from 1 to 24 {
  .zan-col-#{$i} { width: $i * 100% / 24; }
  .zan-col-offset-#{$i} { margin-left: $i * 100% / 24; }
}


================================================
FILE: src/zanui/color.scss
================================================
@import 'common';

.zan-c-red {
  color: $red !important;
}

.zan-c-gray {
  color: $gray !important;
}

.zan-c-gray-dark {
  color: $gray-dark !important;
}

.zan-c-gray-darker {
  color: $gray-darker !important;
}

.zan-c-black {
  color: $text-color !important;
}

.zan-c-blue {
  color: $blue !important;
}

.zan-c-green {
  color: $green !important;
}


================================================
FILE: src/zanui/common.scss
================================================
/* color variables */
$black: #000;
$white: #fff;
$red: #f44;
$blue: #38f;
$orange: #f60;
$green: #06bf04;
$gray: #c9c9c9;
$gray-light: #e5e5e5;
$gray-darker: #666;
$gray-dark: #999;

/* default colors */
$text-color: #333;
$border-color: #ccc;
$active-color: #e8e8e8;
$background-color: #f8f8f8;

/* button */
$button-default-color: $text-color;
$button-default-background-color: $white;
$button-default-border-color: $gray-light;
$button-primary-color: $white;
$button-primary-background-color: #4b0;
$button-primary-border-color: #0a0;
$button-danger-color: $white;
$button-danger-background-color: $red;
$button-danger-border-color: #e33;
$button-disabled-color: $gray-dark;
$button-disabled-background-color: $gray-light;
$button-disabled-border-color: $border-color;
$button-bottom-action-default-color: $white;
$button-bottom-action-default-background-color: #f85;
$button-bottom-action-primary-color: $white;
$button-bottom-action-primary-background-color: $red;

@mixin hairline($border-retina-color: $gray-light) {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 200%;
  height: 200%;
  transform: scale(.5);
  transform-origin: 0 0;
  pointer-events: none;
  box-sizing: border-box;
  border: 0 solid $border-retina-color;
}


================================================
FILE: src/zanui/helper.scss
================================================
@import "common";

.zan-pull-left {
  float: left;
}

.zan-pull-right {
  float: right;
}

.zan-center {
  text-align: center;
}

.zan-right {
  text-align: right;
}

.zan-text-deleted {
  text-decoration: line-through;
}
.zan-font-8 {
  font-size: 8px;
}
.zan-font-10 {
  font-size: 10px;
}
.zan-font-12 {
  font-size: 12px;
}
.zan-font-14 {
  font-size: 14px;
}
.zan-font-16 {
  font-size: 16px;
}
.zan-font-18 {
  font-size: 18px;
}
.zan-font-20 {
  font-size: 20px;
}
.zan-font-22 {
  font-size: 22px;
}
.zan-font-24 {
  font-size: 22px;
}
.zan-font-30 {
  font-size: 30px;
}
.zan-font-bold {
  font-weight: bold;
}

.zan-arrow {
  position: absolute;
  right: 15px;
  top: 50%;
  display: inline-block;
  height: 6px;
  width: 6px;
  border-width: 2px 2px 0 0;
  border-color: #c8c8c8;
  border-style: solid;
  transform: translateY(-50%) matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
}

.zan-ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  word-wrap: normal;
}

.zan-ellipsis--l2 {
  max-height: 40px;
  line-height: 20px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.zan-ellipsis--l3 {
  max-height: 60px;
  line-height: 20px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

.zan-clearfix {
  zoom: 1;
}
.zan-clearfix::after {
  content: '';
  display: table;
  clear: both;
}

/* 超细边框 */
.zan-hairline {
  &,
  &--top,
  &--left,
  &--right,
  &--bottom,
  &--top-bottom,
  &--surround {
    position: relative;

    &::after {
      @include hairline;
    }
  }

  &--top::after {
    border-top-width: 1px;
  }

  &--left::after {
    border-left-width: 1px;
  }

  &--right::after {
    border-right-width: 1px;
  }

  &--bottom::after {
    border-bottom-width: 1px;
  }

  &--top-bottom::after {
    border-width: 1px 0;
  }

  &--surround::after {
    border-width: 1px;
  }
}


================================================
FILE: src/zanui/icon.scss
================================================
/* DO NOT EDIT! Generated by fount */

@font-face {
  font-family: 'zanui-weapp-icon';
  src: url('https://b.yzcdn.cn/zanui-weapp/zanui-weapp-icon-4381aded05.eot');
  src: url('https://b.yzcdn.cn/zanui-weapp/zanui-weapp-icon-4381aded05.eot?#iefix') format('embedded-opentype'),
       url('https://b.yzcdn.cn/zanui-weapp/zanui-weapp-icon-4381aded05.woff2') format('woff2'),
       url('https://b.yzcdn.cn/zanui-weapp/zanui-weapp-icon-4381aded05.woff') format('woff'),
       url('https://b.yzcdn.cn/zanui-weapp/zanui-weapp-icon-4381aded05.ttf') format('truetype')
}

.zan-icon {
    display: inline-block;
}
.zan-icon::before {
  font-family: "zanui-weapp-icon" !important;
  font-style: normal;
  font-weight: normal;
  speak: none;

  display: inline-block;
  text-decoration: inherit;
  width: 1em;
  text-align: center;

  /* For safety - reset parent styles, that can break glyph codes*/
  font-variant: normal;
  text-transform: none;

  /* fix buttons height, for twitter bootstrap */
  line-height: 1em;

  /* Animation center compensation - margins should be symmetric */
  /* remove if not needed */
  /* margin-left: .2em; */

  /* you can be more comfortable with increased icons size */
  /* font-size: 120%; */

  /* Font smoothing. That was taken from TWBS */
  -webkit-font-smoothing: antialiased;

  /* Uncomment for 3D effect */
  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
/* DO NOT EDIT! Generated by iconfount */


.zan-icon-qr-invalid:before { content: '\e800'; } /* '' */
.zan-icon-qr:before { content: '\e801'; } /* '' */
.zan-icon-exchange:before { content: '\e802'; } /* '' */
.zan-icon-close:before { content: '\e803'; } /* '' */
.zan-icon-location:before { content: '\e804'; } /* '' */
.zan-icon-upgrade:before { content: '\e805'; } /* '' */
.zan-icon-check:before { content: '\e806'; } /* '' */
.zan-icon-checked:before { content: '\e807'; } /* '' */
.zan-icon-like-o:before { content: '\e808'; } /* '' */
.zan-icon-like:before { content: '\e809'; } /* '' */
.zan-icon-chat:before { content: '\e80a'; } /* '' */
.zan-icon-shop:before { content: '\e80b'; } /* '' */
.zan-icon-photograph:before { content: '\e80c'; } /* '' */
.zan-icon-add:before { content: '\e80d'; } /* '' */
.zan-icon-add2:before { content: '\e80e'; } /* '' */
.zan-icon-photo:before { content: '\e80f'; } /* '' */
.zan-icon-logistics:before { content: '\e810'; } /* '' */
.zan-icon-edit:before { content: '\e811'; } /* '' */
.zan-icon-passed:before { content: '\e812'; } /* '' */
.zan-icon-cart:before { content: '\e813'; } /* '' */
.zan-icon-shopping-cart:before { content: '\e814'; } /* '' */
.zan-icon-arrow:before { content: '\e815'; } /* '' */
.zan-icon-gift:before { content: '\e816'; } /* '' */
.zan-icon-search:before { content: '\e817'; } /* '' */
.zan-icon-clear:before { content: '\e818'; } /* '' */
.zan-icon-success:before { content: '\e819'; } /* '' */
.zan-icon-fail:before { content: '\e81a'; } /* '' */
.zan-icon-contact:before { content: '\e81b'; } /* '' */
.zan-icon-wechat:before { content: '\e81c'; } /* '' */
.zan-icon-alipay:before { content: '\e81d'; } /* '' */
.zan-icon-password-view:before { content: '\e81e'; } /* '' */
.zan-icon-password-not-view:before { content: '\e81f'; } /* '' */
.zan-icon-wap-nav:before { content: '\e820'; } /* '' */
.zan-icon-wap-home:before { content: '\e821'; } /* '' */
.zan-icon-ecard-pay:before { content: '\e822'; } /* '' */
.zan-icon-balance-pay:before { content: '\e823'; } /* '' */
.zan-icon-peer-pay:before { content: '\e824'; } /* '' */
.zan-icon-credit-pay:before { content: '\e825'; } /* '' */
.zan-icon-debit-pay:before { content: '\e826'; } /* '' */
.zan-icon-other-pay:before { content: '\e827'; } /* '' */
.zan-icon-browsing-history:before { content: '\e828'; } /* '' */
.zan-icon-goods-collect:before { content: '\e829'; } /* '' */
.zan-icon-shop-collect:before { content: '\e82a'; } /* '' */
.zan-icon-receive-gift:before { content: '\e82b'; } /* '' */
.zan-icon-send-gift:before { content: '\e82c'; } /* '' */
.zan-icon-setting:before { content: '\e82d'; } /* '' */
.zan-icon-points:before { content: '\e82e'; } /* '' */
.zan-icon-coupon:before { content: '\e82f'; } /* '' */
.zan-icon-free-postage:before { content: '\e830'; } /* '' */
.zan-icon-discount:before { content: '\e831'; } /* '' */
.zan-icon-birthday-privilege:before { content: '\e832'; } /* '' */
.zan-icon-member-day-privilege:before { content: '\e833'; } /* '' */
.zan-icon-balance-details:before { content: '\e834'; } /* '' */
.zan-icon-cash-back-record:before { content: '\e835'; } /* '' */
.zan-icon-points-mall:before { content: '\e836'; } /* '' */
.zan-icon-exchange-record:before { content: '\e837'; } /* '' */
.zan-icon-pending-payment:before { content: '\e838'; } /* '' */
.zan-icon-pending-orders:before { content: '\e839'; } /* '' */
.zan-icon-pending-deliver:before { content: '\e83a'; } /* '' */
.zan-icon-pending-evaluate:before { content: '\e83b'; } /* '' */
.zan-icon-gift-card-pay:before { content: '\e83c'; } /* '' */
.zan-icon-cash-on-deliver:before { content: '\e83d'; } /* '' */
.zan-icon-underway:before { content: '\e83e'; } /* '' */
.zan-icon-point-gift:before { content: '\e83f'; } /* '' */
.zan-icon-after-sale:before { content: '\e840'; } /* '' */
.zan-icon-edit-data:before { content: '\e841'; } /* '' */
.zan-icon-question:before { content: '\e842'; } /* '' */
.zan-icon-delete:before { content: '\e843'; } /* '' */
.zan-icon-records:before { content: '\e844'; } /* '' */
.zan-icon-description:before { content: '\e845'; } /* '' */
.zan-icon-card:before { content: '\e846'; } /* '' */
.zan-icon-gift-card:before { content: '\e847'; } /* '' */
.zan-icon-clock:before { content: '\e848'; } /* '' */
.zan-icon-gold-coin:before { content: '\e849'; } /* '' */
.zan-icon-completed:before { content: '\e84a'; } /* '' */
.zan-icon-value-card:before { content: '\e84b'; } /* '' */
.zan-icon-certificate:before { content: '\e84c'; } /* '' */
.zan-icon-tosend:before { content: '\e84d'; } /* '' */
.zan-icon-sign:before { content: '\e84e'; } /* '' */
.zan-icon-home:before { content: '\e84f'; } /* '' */
.zan-icon-phone:before { content: '\e850'; } /* '' */
.zan-icon-add-o:before { content: '\e851'; } /* '' */
.zan-icon-play:before { content: '\e852'; } /* '' */
.zan-icon-pause:before { content: '\e853'; } /* '' */
.zan-icon-stop:before { content: '\e854'; } /* '' */
.zan-icon-hot:before { content: '\e855'; } /* '' */
.zan-icon-new:before { content: '\e856'; } /* '' */
.zan-icon-new-arrival:before { content: '\e857'; } /* '' */
.zan-icon-hot-sale:before { content: '\e858'; } /* '' */


================================================
FILE: src/zanui/panel.scss
================================================
@import "common";

.zan-panel {
  position: relative;
  background: #fff;
  margin-top: 10px;
  overflow: hidden;

  &::after {
    @include hairline;
    border-top-width: 1px;
    border-bottom-width: 1px;
  }
}

.zan-panel-title {
  font-size: 14px;
  line-height: 1;
  color: #999;
  padding: 20px 15px 0 15px;
}


.zan-panel--without-margin-top {
  margin-top: 0;
}

.zan-panel--without-border {
  &::after {
    border: 0 none;
  }
}


================================================
FILE: src/zanui/row.scss
================================================
.zan-row {
  &:after {
    content: "";
    display: table;
    clear: both;
  }
}


================================================
FILE: src/zanui/tag.scss
================================================
@import "common";

.zan-tag {
  display: inline-block;
  position: relative;
  box-sizing: border-box;
  line-height: 16px;
  padding: 0 5px;
  border-radius: 2px;
  font-size: 11px;
  background: $gray;
  text-align: center;
  color: $white;

  &::after {
    @include hairline;
    border-width: 1px;
    border-radius: 4px;
  }
}

.zan-tag--plain {
  color: $gray;
  background: $white;
}

/* 各种主题代码 */
.zan-tag--primary {
  color: $button-primary-color;
  background-color: $button-primary-background-color;

  &::after {
    border-color: $button-primary-background-color;
  }

  /* 空心形式 */
  &.zan-tag--plain {
    color: $button-primary-background-color;
    background: $white;
  }
}

.zan-tag--danger {
  color: $button-danger-color;
  background: $button-danger-background-color;

  &::after {
    border-color: $button-danger-background-color;
  }

  /* 空心形式 */
  &.zan-tag--plain {
    color: $button-danger-background-color;
    background: $button-danger-color;
  }
}

.zan-tag--warn {
  color: $white;
  background: #f85;

  &::after {
    border-color: #f85;
  }

  /* 空心形式 */
  &.zan-tag--plain {
    color: #f85;
    background: $white;
  }
}


/* disabled tag */
.zan-tag--disabled {
  color: $button-disabled-color !important;
  background: $button-disabled-background-color;

  &::after {
    border-color: $button-disabled-border-color;
  }
}



================================================
FILE: wepy.config.js
================================================
module.exports = {
  eslint: true,
  wpyExt: '.wpy',
  compilers: {
    sass: {
      outputStyle: 'compressed'
    },
    babel: {
      sourceMap: true,
      presets: ['es2015', 'stage-1'],
      plugins: ['transform-export-extensions', 'syntax-export-extensions']
    }
  }
}
Download .txt
gitextract_deywg9a2/

├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── src/
│   ├── app.wpy
│   ├── components/
│   │   ├── zan-actionsheet.wpy
│   │   ├── zan-capsule.wpy
│   │   ├── zan-dialog.wpy
│   │   ├── zan-field.wpy
│   │   ├── zan-loadmore.wpy
│   │   ├── zan-noticebar.wpy
│   │   ├── zan-popup.wpy
│   │   ├── zan-select.wpy
│   │   ├── zan-stepper.wpy
│   │   ├── zan-steps.wpy
│   │   ├── zan-switch.wpy
│   │   ├── zan-tab.wpy
│   │   ├── zan-toast.wpy
│   │   └── zan-toptips.wpy
│   ├── example/
│   │   ├── actionsheet.wpy
│   │   ├── badge.wpy
│   │   ├── btn.wpy
│   │   ├── capsule.wpy
│   │   ├── card.wpy
│   │   ├── cell.wpy
│   │   ├── dashboard.wpy
│   │   ├── dialog.wpy
│   │   ├── field.wpy
│   │   ├── helper.wpy
│   │   ├── icon.wpy
│   │   ├── label.wpy
│   │   ├── layout.wpy
│   │   ├── loadmore.wpy
│   │   ├── noticebar.wpy
│   │   ├── panel.wpy
│   │   ├── popup.wpy
│   │   ├── select.wpy
│   │   ├── stepper.wpy
│   │   ├── steps.wpy
│   │   ├── switch.wpy
│   │   ├── tab.wpy
│   │   ├── tag.wpy
│   │   ├── toast.wpy
│   │   └── toptips.wpy
│   └── zanui/
│       ├── badge.scss
│       ├── btn.scss
│       ├── card.scss
│       ├── cell.scss
│       ├── col.scss
│       ├── color.scss
│       ├── common.scss
│       ├── helper.scss
│       ├── icon.scss
│       ├── panel.scss
│       ├── row.scss
│       └── tag.scss
└── wepy.config.js
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (139K chars).
[
  {
    "path": ".editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": ".eslintignore",
    "chars": 7,
    "preview": "dist/*\n"
  },
  {
    "path": ".eslintrc.js",
    "chars": 931,
    "preview": "module.exports = {\n  root: true,\n  parser: 'babel-eslint',\n  parserOptions: {\n    sourceType: 'module'\n  },\n  env: {\n   "
  },
  {
    "path": ".gitignore",
    "chars": 119,
    "preview": "dist/\nnode_modules/\nweb/style\nsftp-config.json\nlog\nnpm-debug.log\n.vscode\ncoverage\nlerna-debug.log\n.DS_Store\n.wepycache\n"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2016 wepyjs\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 4087,
    "preview": "# ZanUI in WePY\n\n[ZanUI](https://github.com/youzan/zanui-weapp) 有赞移动 Web UI 规范 ZanUI 的小程序现实版本,结合了微信的视觉规范,为用户提供更加统一的使用感受。"
  },
  {
    "path": "package.json",
    "chars": 1145,
    "preview": "{\n  \"name\": \"wepy-wechat-demo\",\n  \"version\": \"2.4.4\",\n  \"description\": \"基于有赞zanui-weapp的wepy组件库\",\n  \"main\": \"dist/app.js"
  },
  {
    "path": "src/app.wpy",
    "chars": 1600,
    "preview": "<style lang=\"css\">\n@import '/zanui/helper.wxss';\n\n.container {\n  background: #f9f9f9;\n  overflow: hidden;\n  min-height: "
  },
  {
    "path": "src/components/zan-actionsheet.wpy",
    "chars": 5559,
    "preview": "<style lang=\"scss\">\n@import '../zanui/btn.scss';\n@import '../zanui/common';\n\n.zan-actionsheet {\n  background-color: #f8f"
  },
  {
    "path": "src/components/zan-capsule.wpy",
    "chars": 1670,
    "preview": "<style lang=\"scss\">\n.zan-capsule {\n  display: inline-block;\n  font-size: 12px;\n  vertical-align: middle;\n  line-height: "
  },
  {
    "path": "src/components/zan-dialog.wpy",
    "chars": 5252,
    "preview": "<style lang=\"scss\">\n@import '../zanui/common';\n\n/* 基础样式 */\n.zan-dialog--container {\n  position: fixed;\n  top: 45%;\n  lef"
  },
  {
    "path": "src/components/zan-field.wpy",
    "chars": 3217,
    "preview": "<style lang=\"scss\">\n@import '../zanui/cell.scss';\n\n.zan-field {\n  padding: 7px 15px;\n  color: #333;\n}\n\n.zan-field--wrapp"
  },
  {
    "path": "src/components/zan-loadmore.wpy",
    "chars": 5093,
    "preview": "<style lang=\"scss\">\n@import '../zanui/common';\n\n.zan-loadmore {\n  position: relative;\n  width: 65%;\n  margin: 21px auto;"
  },
  {
    "path": "src/components/zan-noticebar.wpy",
    "chars": 2815,
    "preview": "<style lang=\"scss\">\n.zan-noticebar {\n  color: #f60;\n  padding: 9px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  backgr"
  },
  {
    "path": "src/components/zan-popup.wpy",
    "chars": 2645,
    "preview": "<style lang=\"scss\">\n.zan-popup {\n  visibility: hidden;\n}\n.zan-popup--show {\n  visibility: visible;\n}\n.zan-popup__mask {\n"
  },
  {
    "path": "src/components/zan-select.wpy",
    "chars": 1441,
    "preview": "<style lang=\"scss\">\n@import '../zanui/cell.scss';\n.zan-select__list .zan-select__radio {\n  display: none;\n}\n</style>\n<te"
  },
  {
    "path": "src/components/zan-stepper.wpy",
    "chars": 3347,
    "preview": "<style lang=\"less\">\n.zan-stepper {\n  color: #666;\n}\n\n.zan-stepper view {\n  display: inline-block;\n  line-height: 20px;\n "
  },
  {
    "path": "src/components/zan-steps.wpy",
    "chars": 5531,
    "preview": "<style lang=\"scss\">\n.zan-steps--steps.zan-steps--5 .zan-steps__step {\n  width: 25%;\n}\n\n.zan-steps--steps.zan-steps--4 .z"
  },
  {
    "path": "src/components/zan-switch.wpy",
    "chars": 2726,
    "preview": "<style lang=\"scss\">\n.zan-switch {\n  position: relative;\n  display: inline-block;\n  width: 52px;\n  height: 32px;\n  vertic"
  },
  {
    "path": "src/components/zan-tab.wpy",
    "chars": 2960,
    "preview": "<style lang=\"scss\">\n.zan-tab {\n  height: 45px;\n}\n.zan-tab__bd {\n  width: 750rpx;\n  display: flex;\n  flex-direction: row;"
  },
  {
    "path": "src/components/zan-toast.wpy",
    "chars": 1199,
    "preview": "<style lang=\"less\">\n.zan-toast {\n  position: fixed;\n  top: 35%;\n  left: 20%;\n  transform: translateZ(0) translateY(-100%"
  },
  {
    "path": "src/components/zan-toptips.wpy",
    "chars": 1962,
    "preview": "<style lang=\"scss\">\n.zan-toptips {\n  display: block;\n  position: fixed;\n  transform: translateY(-100%);\n  width: 100%;\n "
  },
  {
    "path": "src/example/actionsheet.wpy",
    "chars": 1944,
    "preview": "<style lang=\"css\">\n@import '/zanui/btn.wxss';\n</style>\n\n<template>\n<block>\n<view class=\"container\">\n\n  <view class=\"doc-"
  },
  {
    "path": "src/example/badge.wpy",
    "chars": 1205,
    "preview": "<style lang=\"css\">\n@import '/zanui/badge.wxss';\n\n.demo {\n  padding: 40px 0;\n  display: flex;\n}\n.demo__item {\n  flex: 1;\n"
  },
  {
    "path": "src/example/btn.wpy",
    "chars": 2709,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/btn.wxss';\n</style>\n\n<template>\n  <view class=\"container"
  },
  {
    "path": "src/example/capsule.wpy",
    "chars": 1328,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n\n.zan-capsule + .zan-capsule {\n  margin-left"
  },
  {
    "path": "src/example/card.wpy",
    "chars": 1426,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/card.wxss';\n@import '/zanui/color.wxss';\n</style>\n\n<temp"
  },
  {
    "path": "src/example/cell.wpy",
    "chars": 3784,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n@import '/zanui/icon.wxss';\n</style>\n\n<templ"
  },
  {
    "path": "src/example/dashboard.wpy",
    "chars": 3471,
    "preview": "<style lang='css'>\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n\n.logo {\n  display: block;\n  margin: 40px au"
  },
  {
    "path": "src/example/dialog.wpy",
    "chars": 2650,
    "preview": "<style lang=\"css\">\n@import '/zanui/btn.wxss';\n\n</style>\n\n<template>\n<block>\n  <view class=\"container\">\n\n    <view class="
  },
  {
    "path": "src/example/field.wpy",
    "chars": 5823,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/btn.wxss';\n.field__title--radius {\n  padding-bottom: 10p"
  },
  {
    "path": "src/example/helper.wpy",
    "chars": 2500,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n@import '/zanui/color.wxss';\n</style>\n\n<temp"
  },
  {
    "path": "src/example/icon.wpy",
    "chars": 2498,
    "preview": "<style lang=\"css\">\n@import '/zanui/icon.wxss';\n\n.icon-wrap {\n  width: 33.33333%;\n  height: 100px;\n  float: left;\n  text-"
  },
  {
    "path": "src/example/label.wpy",
    "chars": 1150,
    "preview": "<style lang=\"less\">\n\n</style>\n\n<template>\n  <view class=\"container\">\n\n    <view class=\"doc-title\">LABEL</view>\n\n    <vie"
  },
  {
    "path": "src/example/layout.wpy",
    "chars": 1479,
    "preview": "<style lang='css'>\n@import '/zanui/panel.wxss';\n@import '/zanui/col.wxss';\n@import '/zanui/row.wxss';\n\n.zan-col {\n  line"
  },
  {
    "path": "src/example/loadmore.wpy",
    "chars": 723,
    "preview": "<style lang=\"css\">\n\n</style>\n\n<template>\n<view class=\"container\">\n\n  <view class=\"doc-title zan-hairline--bottom\">LOADMO"
  },
  {
    "path": "src/example/noticebar.wpy",
    "chars": 1498,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n\n</style>\n\n<template>\n<view class=\"container"
  },
  {
    "path": "src/example/panel.wpy",
    "chars": 784,
    "preview": "<style lang='css'>\n@import '/zanui/panel.wxss';\n</style>\n\n<template>\n<view class=\"container\">\n\n  <view class=\"doc-title "
  },
  {
    "path": "src/example/popup.wpy",
    "chars": 2175,
    "preview": "<style lang=\"css\">\n@import '/zanui/btn.wxss';\n</style>\n\n<template>\n<view class=\"container\">\n\n  <view class=\"doc-title za"
  },
  {
    "path": "src/example/select.wpy",
    "chars": 2200,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/btn.wxss';\n</style>\n\n<template>\n<block>\n  <view class=\"c"
  },
  {
    "path": "src/example/stepper.wpy",
    "chars": 1420,
    "preview": "<style lang=\"less\">\n.zan-panel {\n  padding: 10px;\n}\n\n.zan-switch {\n  margin-right: 8px;\n}\n</style>\n\n<template>\n  <view c"
  },
  {
    "path": "src/example/steps.wpy",
    "chars": 3653,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n.my-class {\n  padding: 10px;\n}\n.my-class .za"
  },
  {
    "path": "src/example/switch.wpy",
    "chars": 1843,
    "preview": "<style lang=\"css\">\n@import '/zanui/panel.wxss';\n@import '/zanui/card.wxss';\n\n.zan-panel {\n  padding: 10px;\n}\n\n.zan-switc"
  },
  {
    "path": "src/example/tab.wpy",
    "chars": 2356,
    "preview": "<style lang=\"css\">\n\n</style>\n\n<template>\n  <view class=\"container\">\n\n    <view class=\"doc-title zan-hairline--bottom\">TA"
  },
  {
    "path": "src/example/tag.wpy",
    "chars": 1514,
    "preview": "<style lang='css'>\n@import '/zanui/panel.wxss';\n@import '/zanui/cell.wxss';\n@import '/zanui/tag.wxss';\n.zan-tag + .zan-t"
  },
  {
    "path": "src/example/toast.wpy",
    "chars": 732,
    "preview": "<style lang=\"css\">\n\n</style>\n\n<template>\n<block>\n  <view class=\"container\">\n\n    <view class=\"doc-title zan-hairline--bo"
  },
  {
    "path": "src/example/toptips.wpy",
    "chars": 755,
    "preview": "<style lang=\"less\">\n\n</style>\n\n<template>\n<block>\n  <view class=\"container\">\n\n    <view class=\"doc-title zan-hairline--b"
  },
  {
    "path": "src/zanui/badge.scss",
    "chars": 452,
    "preview": ".zan-badge {\n  position: relative;\n}\n.zan-badge__count {\n  position: absolute;\n  top: -16px;\n  right: 0px;\n  height: 1.6"
  },
  {
    "path": "src/zanui/btn.scss",
    "chars": 2706,
    "preview": "@import \"common\";\n\n.zan-btn {\n  position: relative;\n  color: #333;\n  background-color: #fff;\n  margin-bottom: 10px;\n  pa"
  },
  {
    "path": "src/zanui/card.scss",
    "chars": 749,
    "preview": ".zan-card {\n  margin-left: 0px;\n  width: auto;\n  padding: 5px 15px;\n  overflow: hidden;\n  position: relative;\n  font-siz"
  },
  {
    "path": "src/zanui/cell.scss",
    "chars": 1316,
    "preview": "@import \"common\";\n\n.zan-cell {\n  position: relative;\n  padding: 12px 15px;\n  display: flex;\n  align-items: center;\n  lin"
  },
  {
    "path": "src/zanui/col.scss",
    "chars": 193,
    "preview": ".zan-col {\n  float: left;\n  box-sizing: border-box;\n  width: 0;\n}\n\n@for $i from 1 to 24 {\n  .zan-col-#{$i} { width: $i *"
  },
  {
    "path": "src/zanui/color.scss",
    "chars": 357,
    "preview": "@import 'common';\n\n.zan-c-red {\n  color: $red !important;\n}\n\n.zan-c-gray {\n  color: $gray !important;\n}\n\n.zan-c-gray-dar"
  },
  {
    "path": "src/zanui/common.scss",
    "chars": 1255,
    "preview": "/* color variables */\n$black: #000;\n$white: #fff;\n$red: #f44;\n$blue: #38f;\n$orange: #f60;\n$green: #06bf04;\n$gray: #c9c9c"
  },
  {
    "path": "src/zanui/helper.scss",
    "chars": 1989,
    "preview": "@import \"common\";\n\n.zan-pull-left {\n  float: left;\n}\n\n.zan-pull-right {\n  float: right;\n}\n\n.zan-center {\n  text-align: c"
  },
  {
    "path": "src/zanui/icon.scss",
    "chars": 6653,
    "preview": "/* DO NOT EDIT! Generated by fount */\n\n@font-face {\n  font-family: 'zanui-weapp-icon';\n  src: url('https://b.yzcdn.cn/za"
  },
  {
    "path": "src/zanui/panel.scss",
    "chars": 440,
    "preview": "@import \"common\";\n\n.zan-panel {\n  position: relative;\n  background: #fff;\n  margin-top: 10px;\n  overflow: hidden;\n\n  &::"
  },
  {
    "path": "src/zanui/row.scss",
    "chars": 83,
    "preview": ".zan-row {\n  &:after {\n    content: \"\";\n    display: table;\n    clear: both;\n  }\n}\n"
  },
  {
    "path": "src/zanui/tag.scss",
    "chars": 1366,
    "preview": "@import \"common\";\n\n.zan-tag {\n  display: inline-block;\n  position: relative;\n  box-sizing: border-box;\n  line-height: 16"
  },
  {
    "path": "wepy.config.js",
    "chars": 280,
    "preview": "module.exports = {\n  eslint: true,\n  wpyExt: '.wpy',\n  compilers: {\n    sass: {\n      outputStyle: 'compressed'\n    },\n "
  }
]

About this extraction

This page contains the full source code of the brucx/wepy-zanui-demo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (121.1 KB), approximately 39.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!