zhuzhida 5 年 前
コミット
bb80ad86b4

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+.DS_Store
+node_modules
+/dist
+/libs
+/jd
+yarn.lock
+package.lock
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 京东前端
+
+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.

+ 11 - 0
README.md

@@ -0,0 +1,11 @@
+# NutUI 3
+![npm version](https://img.shields.io/npm/v/@nutui/nutui.svg)  [![Build Status](https://api.travis-ci.org/jdf2e/nutui.svg?branch=master)](https://github.com/jdf2e/nutui/) [![Coverage Status](https://coveralls.io/repos/github/jdf2e/nutui/badge.svg?branch=master)](https://coveralls.io/github/jdf2e/nutui?branch=master) ![license](https://img.shields.io/npm/l/@nutui/nutui.svg)
+ 
+Vue3.0 一套移动端轻量级组件库
+    
+![NutUI](https://img11.360buyimg.com/uba/jfs/t1/11117/21/3608/18942/5c20ab52E35e5a500/02e3c1f89cd3dad1.png)
+
+
+## 开源协议
+
+本项目基于 **MIT** 协议

+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  presets: ["@vue/cli-plugin-babel/preset"]
+};

+ 92 - 0
package.json

@@ -0,0 +1,92 @@
+{
+  "name": "@nutui/nutui",
+  "version": "3.0.0-beta.0",
+  "npm": {
+    "tag": "next"
+  },
+  "description": "一套京东风格的轻量级移动端 Vue 组件库",
+  "main": "dist/lib/nutui.js",
+  "module": "dist/es/nutui.js",
+  "style": "dist/lib/index.css",
+  "typings": "dist/types/index.d.ts",
+  "keywords": [
+    "nutui",
+    "nutui2",
+    "nutui3",
+    "vue",
+    "vue3",
+    "webpack",
+    "vue component",
+    "vue3 component",
+    "jdc",
+    "jdcfe"
+  ],
+  "author": "jdcfe",
+  "license": "MIT",
+  "files": [
+    "dist",
+    "README.md",
+    "package.json",
+    "LICENSE",
+    "CHANGELOG.md"
+  ],
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "core-js": "^3.6.5",
+    "sass": "^1.27.0",
+    "sass-loader": "^10.0.4",
+    "vue": "^3.0.0",
+    "vue-router": "^4.0.0-0"
+  },
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^2.33.0",
+    "@typescript-eslint/parser": "^2.33.0",
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-typescript": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/compiler-sfc": "^3.0.0",
+    "@vue/eslint-config-prettier": "^6.0.0",
+    "@vue/eslint-config-typescript": "^5.0.2",
+    "eslint": "^6.7.2",
+    "eslint-plugin-prettier": "^3.1.3",
+    "eslint-plugin-vue": "^7.0.0-0",
+    "prettier": "^1.19.1",
+    "typescript": "~3.9.3"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/vue3-essential",
+      "eslint:recommended",
+      "@vue/typescript/recommended",
+      "@vue/prettier",
+      "@vue/prettier/@typescript-eslint"
+    ],
+    "parserOptions": {
+      "ecmaVersion": 2020
+    },
+    "rules": {
+      "vue/no-unused-components": "off",
+      "no-debugger": "off",
+      "no-console": "off"
+    }
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jdf2e/nutui.git"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

+ 47 - 0
src/config.ts

@@ -0,0 +1,47 @@
+export const versions = [
+    { name: "1.x", link: "/1x/" },
+    { name: "2.x", link: "/" },
+    { name: "3.x", link: "/3x/" }
+];
+export const nav = [
+    {
+        name: "布局组件",
+        packages: [
+            {
+                name: "Button",
+                sort: 1,
+                cName: "按钮组件",
+                type: "component",
+                show: true,
+                desc: "按钮用于触发一个操作,如提交表单。",
+                author: "richard1015"
+            }
+        ]
+    },
+    {
+        name: "操作反馈",
+        packages: []
+    },
+    {
+        name: "基础组件",
+        packages: [
+            {
+                name: "Uploader",
+                sort: 1,
+                cName: "上传组件",
+                type: "component",
+                show: true,
+                desc: "",
+                author: "richard1015"
+            }
+        ]
+    },
+    {
+        name: "导航组件",
+        packages: []
+    },
+    {
+        name: "业务组件",
+        packages: []
+    }
+];

+ 1 - 0
src/nutui.ts

@@ -0,0 +1 @@
+export default {};

+ 42 - 0
src/packages/button/demo.vue

@@ -0,0 +1,42 @@
+<template>
+  <div class="demo">
+    <div class="title">类型</div>
+    <div class="card">
+      <nut-button type="primary">主要按钮</nut-button>
+      <nut-button type="success">成功按钮</nut-button>
+      <nut-button type="default">默认按钮</nut-button>
+      <nut-button type="warning">警告按钮</nut-button>
+      <nut-button type="danger">危险按钮</nut-button>
+    </div>
+    <div class="title">通栏</div>
+    <div class="card">
+      <nut-button block>通栏按钮 Normer</nut-button>
+      <nut-button block>通栏按钮 Pressed</nut-button>
+      <nut-button block disabled>通栏按钮 Disabled</nut-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import Button from "@/packages/button/index.vue";
+import { createDemoComponent } from "@/utils/create";
+export default createDemoComponent("button")({
+  props: {
+    text: String
+  },
+  components: { "nut-button": Button },
+  emits: ["click"],
+  setup(props, { emit, slots }) {
+    console.log(props);
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.nut-button {
+  margin-bottom: 21px;
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+</style>

+ 22 - 0
src/packages/button/doc.md

@@ -0,0 +1,22 @@
+# Button
+
+### 介绍
+
+按钮组件,触发操作
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { Button } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Button);
+
+```
+
+### 代码示例
+
+#### 按钮类型
+
+按钮支持 `default`、`primary`、`success`、`warning`、`danger` 五种类型,默认为 default。

+ 10 - 0
src/packages/button/index.scss

@@ -0,0 +1,10 @@
+.nut-button {
+    display: block;
+    background: $button-default-bg-color;
+    color: $button-default-color;
+    font-size: $button-default-font-size;
+    line-height: $button-default-height;
+    height: $button-default-height;
+    border-radius: $button-border-radius;
+    text-align: center;
+}

+ 41 - 0
src/packages/button/index.vue

@@ -0,0 +1,41 @@
+<template>
+  <view class="nut-button" :disabled="disabled" @click="clickHandler">
+    <slot></slot>
+  </view>
+</template>
+
+<script lang="ts">
+import { PropType } from "vue";
+import { createComponent } from "@/utils/create";
+export type ButtonType =
+  | "default"
+  | "primary"
+  | "success"
+  | "warning"
+  | "danger";
+export type ButtonSize = "large" | "normal" | "small" | "mini";
+export default createComponent("button")({
+  props: {
+    text: String,
+    color: String,
+    disabled: Boolean,
+    type: {
+      type: String as PropType<ButtonType>,
+      default: "default"
+    },
+    size: {
+      type: String as PropType<ButtonSize>,
+      default: "normal"
+    }
+  },
+  components: {},
+  emits: ["click"],
+  setup(props, { emit, slots }) {
+    console.log(props);
+  }
+});
+</script>
+
+<style lang="scss">
+@import "index.scss";
+</style>

+ 5 - 0
src/shims-vue.d.ts

@@ -0,0 +1,5 @@
+declare module '*.vue' {
+  import type { DefineComponent } from 'vue'
+  const component: DefineComponent<{}, {}, any>
+  export default component
+}

BIN
src/sites/assets/images/logo.png


+ 120 - 0
src/sites/assets/styles/reset.scss

@@ -0,0 +1,120 @@
+@charset "utf-8";
+html,
+body,
+div,
+span,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+em,
+img,
+s,
+strong,
+b,
+u,
+i,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section,
+time,
+audio,
+video {
+    margin: 0;
+    padding: 0;
+    border: 0;
+    font: inherit;
+    -webkit-overflow-scrolling: touch;
+}
+
+/* ios默认文本框阴影 */
+
+input[type="text"],
+textarea {
+    -webkit-appearance: none;
+}
+
+/* 低版本安卓文本框层级问题 */
+
+input:focus {
+    -webkit-user-modify: read-write-plaintext-only;
+}
+
+// 清除谷歌浏览器下的 search 叉号
+input::-webkit-search-cancel-button {
+    display: none;
+}
+
+ol,
+ul {
+    list-style: none;
+}
+
+table {
+    border-collapse: collapse;
+    border-spacing: 0;
+}
+
+* {
+    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+    -webkit-tap-highlight-color: transparent;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -ms-box-sizing: border-box;
+    box-sizing: border-box;
+}
+
+html,
+body,
+a,
+button,
+input {
+    outline: 0 none;
+    border: 0;
+    text-decoration: none;
+}
+
+img {
+    border: 0 none;
+    vertical-align: bottom;
+    -ms-interpolation-mode: bicubic;
+}
+[v-cloak] {
+    display: none;
+}
+html,
+body {
+    height: 100%;
+    width: 100%;
+}

+ 4 - 0
src/sites/assets/util/index.ts

@@ -0,0 +1,4 @@
+const ua = navigator.userAgent.toLowerCase();
+const isMobile = /ios|iphone|ipod|ipad|android/.test(ua);
+
+export { isMobile };

+ 119 - 0
src/sites/doc/App.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="doc-header">
+    NutUI
+  </div>
+  <div class="doc-nav">
+    <ol>
+      <li>指南</li>
+      <ul>
+        <li>介绍</li>
+        <li>快速上手</li>
+        <li>主题定制</li>
+        <li>国际化</li>
+        <li>更新日志</li>
+        <li>资源</li>
+      </ul>
+    </ol>
+    <ol v-for="_nav in nav" :key="_nav">
+      <li>{{ _nav.name }}</li>
+      <ul>
+        <li v-for="_package in _nav.packages" :key="_package">
+          <router-link :to="_package.name.toLocaleLowerCase()">{{ _package.name }}&nbsp;&nbsp;{{ _package.cName }}
+          </router-link>
+        </li>
+      </ul>
+    </ol>
+  </div>
+  <div class="doc-h5-preview">
+    <iframe :src="demoUrl" frameborder="0"></iframe>
+  </div>
+  <router-view />
+</template>
+<script lang="ts">
+import { defineComponent } from "vue";
+import { nav, versions } from "@/config";
+export default defineComponent({
+  name: "doc",
+  components: {},
+  data() {
+    return {
+      nav,
+      versions,
+      demoUrl: `demo.html`
+    };
+  },
+  watch: {
+    $route(to) {
+      const { origin, pathname } = window.location;
+      this.demoUrl = `${origin}${pathname.replace("index.html", "")}demo.html#${
+        to.path
+      }`;
+    }
+  }
+});
+</script>
+
+<style lang="scss">
+#doc {
+  font-family: PingFangSC-Regular;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-text-size-adjust: none;
+  -ms-text-size-adjust: 100%;
+  background: #f7f8fa;
+  height: 100%;
+  width: 100%;
+}
+.doc {
+  &-header {
+    position: fixed;
+    z-index: 2;
+    left: 0;
+    right: 0;
+    background: $button-default-bg-color;
+    height: 57px;
+    line-height: 57px;
+    text-align: left;
+    padding: 0 50px;
+    font-size: 20px;
+    color: $white;
+  }
+
+  &-nav {
+    position: fixed;
+    z-index: 1;
+    background: #fff;
+    width: 220px;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    padding: 80px 20px;
+    > ol {
+      border-bottom: 1px solid red;
+      > li {
+        font-weight: bold;
+      }
+      > ul {
+        li {
+        }
+      }
+    }
+  }
+
+  &-h5-preview {
+    height: 667px;
+    width: 375px;
+    position: fixed;
+    right: 30px;
+    top: 100px;
+    box-shadow: #ebedf0 0 4px 12px;
+    border-radius: 12px;
+    overflow: hidden;
+
+    iframe {
+      height: 100%;
+      width: 100%;
+    }
+  }
+}
+</style>

BIN
src/sites/doc/favicon.ico


+ 85 - 0
src/sites/doc/index.html

@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta content="telephone=no" name="format-detection" />
+    <link rel="shortcut icon" href="https://nutui.jd.com/favicon.ico" />
+    <meta
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
+      name="viewport"
+    />
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
+    <title><%= htmlWebpackPlugin.options.title %></title>
+    <!-- <title>NutUI - 移动端Vue组件库</title> -->
+    <script src="https://h5.m.jd.com/babelDiy/Zeus/2846ykuM7PwipD9E2RzMj2BGEQpA/plugin/share.min.js"></script>
+    <style>
+      html {
+        background: #f7f7f7;
+      }
+
+      a[title="站长统计"] {
+        display: none;
+      }
+    </style>
+    <!-- Hotjar Tracking Code for nutui.jd.com -->
+    <script async>
+      (function(h, o, t, j, a, r) {
+        h.hj =
+          h.hj ||
+          function() {
+            (h.hj.q = h.hj.q || []).push(arguments);
+          };
+        h._hjSettings = { hjid: 1900179, hjsv: 6 };
+        a = o.getElementsByTagName("head")[0];
+        r = o.createElement("script");
+        r.async = 1;
+        r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
+        a.appendChild(r);
+      })(window, document, "https://static.hotjar.com/c/hotjar-", ".js?sv=");
+    </script>
+  </head>
+  <body>
+    <noscript>
+      <strong
+        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
+        properly without JavaScript enabled. Please enable it to
+        continue.</strong
+      >
+    </noscript>
+    <div id="doc"></div>
+    <!-- built files will be auto injected -->
+    <script>
+      //分享配置
+      var shareOption = {
+        iconUrl: "https://nutui.jd.com/img/logo_share.png",
+        url: "https://nutui.jd.com/demo.html#/index",
+        title: "轻量级移动端Vue组件库 - NutUI 3.0",
+        desc: "京东风格的Vue组件库",
+      };
+
+      try {
+        /*初始化分享*/
+        share.shareInit(shareOption);
+      } catch (e) {
+        console.log(e);
+      }
+    </script>
+    <script type="text/javascript">
+      var jaq = jaq || [];
+      jaq.push(["account", "JA2018_1831300"]);
+      jaq.push(["domain", "jd.com"]);
+      (function() {
+        var ja = document.createElement("script");
+        ja.type = "text/javascript";
+        ja.async = true;
+        ja.src = "//wl.jd.com/joya.js";
+        var s = document.getElementsByTagName("script")[0];
+        s.parentNode.insertBefore(ja, s);
+      })();
+    </script>
+    <script
+      type="text/javascript"
+      src="https://s23.cnzz.com/z_stat.php?id=1276268086&web_id=1276268086"
+    ></script>
+  </body>
+</html>

+ 8 - 0
src/sites/doc/main.ts

@@ -0,0 +1,8 @@
+import { createApp } from "vue";
+import App from "./App.vue";
+import router from "./router";
+import "@/sites/assets/styles/reset.scss";
+
+createApp(App)
+  .use(router)
+  .mount("#doc");

+ 29 - 0
src/sites/doc/router.ts

@@ -0,0 +1,29 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
+
+const routes: Array<RouteRecordRaw> = [];
+// import { nav } from '@/config';
+// nav.forEach(item => {
+//   item.packages.forEach(_item => {
+//     if (_item.show) {
+//       routes.push({
+//         path: `/${_item.name}`,
+//         name: _item.name,
+//         components: {
+//         	main: () => import(`@/packages/${_item.name.toLocaleLowerCase()}/demo.vue`),
+//         }
+//       })
+//     }
+//   })
+// })
+
+const files = require.context("@/packages", true, /doc\.md$/);
+files.keys().forEach(component => {
+  // console.log(component)
+});
+
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes
+});
+
+export default router;

+ 76 - 0
src/sites/mobile/App.vue

@@ -0,0 +1,76 @@
+<template>
+  <div id="nav">{{title}}</div>
+  <router-view />
+</template>
+<script lang="ts">
+import { defineComponent } from "vue";
+import { isMobile } from "@/sites/assets/util";
+export default defineComponent({
+  name: "app",
+  components: {},
+  data() {
+    return {
+      title: "NutUI"
+    };
+  },
+  watch: {
+    $route(to) {
+      const { origin, hash, pathname } = window.top.location;
+      if (!isMobile && to.href != hash) {
+        window.top.location.replace(`${origin}${pathname}#/${to.name}`);
+        this.title = to.name;
+      } else {
+        this.title = "";
+      }
+    }
+  }
+});
+</script>
+
+<style lang="scss">
+#app {
+  font-family: PingFangSC-Regular;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-text-size-adjust: none;
+  -ms-text-size-adjust: 100%;
+  background: #fff;
+  height: 100%;
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+
+  #nav {
+    position: fixed;
+    left: 0;
+    right: 0;
+    height: 57px;
+    line-height: 57px;
+    text-align: center;
+    background: #fff;
+    font-family: PingFangSC-Medium;
+    font-size: 20px;
+    color: rgba(51, 51, 51, 1);
+  }
+
+  .demo {
+    padding-top: 57px;
+    height: 100%;
+    background: #f7f8fa;
+    overflow-y: auto;
+
+    .title {
+      padding-left: 25px;
+      height: 56px;
+      line-height: 56px;
+      font-size: 14px;
+      color: rgba(144, 156, 164, 1);
+    }
+
+    .card {
+      padding: 25px 18px;
+      background: rgba(255, 255, 255, 1);
+    }
+  }
+}
+</style>

+ 109 - 0
src/sites/mobile/components/index.vue

@@ -0,0 +1,109 @@
+<template>
+  <div class="index">
+    <div class="index-header">
+      <img src="@/sites/assets/images/logo.png" alt="" srcset="" />
+      <div class="info">
+        <h1>Nut UI</h1>
+        <p>一套京东风格的轻量级移动端 Vue 组件库</p>
+      </div>
+    </div>
+    <div class="index-components">
+      <ol v-for="_nav in nav" :key="_nav">
+        <li>{{ _nav.name }}</li>
+        <ul>
+          <li v-for="_package in _nav.packages" :key="_package">
+            <router-link :to="_package.name.toLocaleLowerCase()"
+              >{{ _package.name }}&nbsp;&nbsp;{{ _package.cName }}
+            </router-link>
+          </li>
+        </ul>
+      </ol>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from "vue";
+import { nav, versions } from "@/config";
+export default defineComponent({
+  name: "doc",
+  components: {},
+  data() {
+    return {
+      nav,
+      versions
+    };
+  }
+});
+</script>
+<style lang="scss" scoped>
+.index {
+  height: 100%;
+  width: 100%;
+  padding-top: 30px;
+
+  &-header {
+    display: flex;
+    align-items: center;
+    padding: 0 34px;
+    height: 117px;
+    > img {
+      width: 67px;
+      height: 67px;
+      margin-right: 18px;
+      flex-shrink: 0;
+    }
+    .info {
+      display: flex;
+      flex-direction: column;
+      h1 {
+        height: 48px;
+        line-height: 48px;
+        font-size: 34px;
+        color: rgba(51, 51, 51, 1);
+      }
+      p {
+        height: 18px;
+        line-height: 18px;
+        font-size: 12px;
+        color: rgba(154, 155, 157, 1);
+      }
+    }
+  }
+  &-components {
+    background: #f7f8fa;
+    border-radius: 30px 30px 0 0;
+    overflow: hidden;
+    padding: 30px 25px;
+    > ol {
+      margin-bottom: 17px;
+      > li {
+        line-height: 20px;
+        font-size: 14px;
+        color: rgba(144, 156, 164, 1);
+        margin-bottom: 10px;
+      }
+      > ul {
+        li {
+          padding: 0 24px;
+          width: 100%;
+          height: 45px;
+          line-height: 45px;
+          background: rgba(255, 255, 255, 1);
+          border-radius: 22px;
+          box-shadow: 0px 1px 4px 0px rgba(102, 102, 102, 0.06);
+          margin-bottom: 13px;
+          a {
+            width: 100%;
+            height: 100%;
+            font-size: 15px;
+            font-weight: bold;
+            display: block;
+            color: rgba(51, 51, 51, 1);
+          }
+        }
+      }
+    }
+  }
+}
+</style>

BIN
src/sites/mobile/favicon.ico


+ 70 - 0
src/sites/mobile/index.html

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta content="telephone=no" name="format-detection" />
+    <link rel="shortcut icon" href="https://nutui.jd.com/favicon.ico" />
+    <meta
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
+      name="viewport"
+    />
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
+    <title><%= htmlWebpackPlugin.options.title %></title>
+    <!-- <title>NutUI - 移动端Vue组件库</title> -->
+    <script src="https://h5.m.jd.com/babelDiy/Zeus/2846ykuM7PwipD9E2RzMj2BGEQpA/plugin/share.min.js"></script>
+    <style>
+      html {
+        background: #f7f7f7;
+      }
+
+      a[title="站长统计"] {
+        display: none;
+      }
+    </style>
+  </head>
+  <body>
+    <noscript>
+      <strong
+        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
+        properly without JavaScript enabled. Please enable it to
+        continue.</strong
+      >
+    </noscript>
+    <div id="app"></div>
+
+    <!-- built files will be auto injected -->
+    <script>
+      //分享配置
+      var shareOption = {
+        iconUrl: "https://nutui.jd.com/img/logo_share.png",
+        url: "https://nutui.jd.com/demo.html#/index",
+        title: "轻量级移动端Vue组件库 - NutUI 3.0",
+        desc: "京东风格的Vue组件库",
+      };
+
+      try {
+        /*初始化分享*/
+        share.shareInit(shareOption);
+      } catch (e) {
+        console.log(e);
+      }
+    </script>
+    <script type="text/javascript">
+      var jaq = jaq || [];
+      jaq.push(["account", "JA2018_1831300"]);
+      jaq.push(["domain", "jd.com"]);
+      (function() {
+        var ja = document.createElement("script");
+        ja.type = "text/javascript";
+        ja.async = true;
+        ja.src = "//wl.jd.com/joya.js";
+        var s = document.getElementsByTagName("script")[0];
+        s.parentNode.insertBefore(ja, s);
+      })();
+    </script>
+    <script
+      type="text/javascript"
+      src="https://s23.cnzz.com/z_stat.php?id=1276268086&web_id=1276268086"
+    ></script>
+  </body>
+</html>

+ 8 - 0
src/sites/mobile/main.ts

@@ -0,0 +1,8 @@
+import { createApp } from "vue";
+import App from "./App.vue";
+import router from "./router";
+import "@/sites/assets/styles/reset.scss";
+
+createApp(App)
+  .use(router)
+  .mount("#app");

+ 33 - 0
src/sites/mobile/router.ts

@@ -0,0 +1,33 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
+import Index from "./components/index.vue";
+const routes: Array<RouteRecordRaw> = [
+  {
+    path: "/",
+    name: "index",
+    component: Index
+  },
+
+];
+
+const files = require.context("@/packages", true, /demo\.vue$/);
+files.keys().forEach(component => {
+  const componentEntity = files(component).default;
+  routes.push({
+    path: `/${componentEntity.baseName}`,
+    name: componentEntity.baseName,
+    component: componentEntity
+  });
+});
+
+routes.push({
+  name: 'NotFound',
+  path: '/:path(.*)+',
+  redirect: () => '/',
+});
+
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes
+});
+
+export default router;

+ 1 - 0
src/styles/index.scss

@@ -0,0 +1 @@
+@import './variable';

+ 29 - 0
src/styles/variables.scss

@@ -0,0 +1,29 @@
+// color
+
+// 主色调
+$primary-color: #fa2c19 !default;
+$primary-color-end: #fa6419 !default;
+// 辅助色
+$help-color: #f5f5f5 !default;
+// 标题常规文字
+$title-color: #1a1a1a !default;
+// 次内容
+$text-color: #808080 !default;
+// 特殊禁用色
+$disable-color: #cccccc !default;
+$white: #fff;
+
+// Font
+$font-size-1: 12px;
+$font-size-2: 14px;
+$font-size-3: 16px;
+$font-size-4: 18px;
+$font-weight-bold: 400;
+
+// button
+$button-border-radius: 25px;
+$button-default-bg-color: linear-gradient(135deg, $primary-color 0%, $primary-color-end 100%);
+$button-default-height: 48px;
+$button-default-line-height: 1.2;
+$button-default-font-size: $font-size-3;
+$button-default-color: $white;

+ 21 - 0
src/utils/create/component.ts

@@ -0,0 +1,21 @@
+import { App, defineComponent, ComponentOptions } from "vue";
+export function createComponent(name: string) {
+  return function(_component: ComponentOptions) {
+    _component.baseName = name;
+    _component.name = "nut-" + name;
+    _component.install = (vue: App) => {
+      vue.component(_component.name as string, _component);
+    };
+    return defineComponent(_component);
+  } as typeof defineComponent;
+}
+export function createDemoComponent(name: string) {
+  return function(_component: ComponentOptions) {
+    _component.baseName = name;
+    _component.name = "demo-" + name;
+    _component.install = (vue: App) => {
+      vue.component(_component.name as string, _component);
+    };
+    return defineComponent(_component);
+  } as typeof defineComponent;
+}

+ 2 - 0
src/utils/create/index.ts

@@ -0,0 +1,2 @@
+import { createComponent, createDemoComponent } from "./component";
+export { createComponent, createDemoComponent };

+ 39 - 0
tsconfig.json

@@ -0,0 +1,39 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "esnext",
+    "strict": true,
+    "jsx": "preserve",
+    "importHelpers": true,
+    "moduleResolution": "node",
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "sourceMap": true,
+    "baseUrl": ".",
+    "types": [
+      "webpack-env"
+    ],
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
+    "lib": [
+      "esnext",
+      "dom",
+      "dom.iterable",
+      "scripthost"
+    ]
+  },
+  "include": [
+    "src/**/*.ts",
+    "src/**/*.tsx",
+    "src/**/*.vue",
+    "tests/**/*.ts",
+    "tests/**/*.tsx"
+  ],
+  "exclude": [
+    "node_modules"
+  ]
+}

+ 58 - 0
vue.config.js

@@ -0,0 +1,58 @@
+// vue.config.js
+module.exports = {
+  productionSourceMap: process.env.NODE_ENV != "production",
+  publicPath: "./",
+  css: {
+    loaderOptions: {
+      // 给 sass-loader 传递选项
+      //   prependData: {
+      //     // @/ 是 src/ 的别名
+      //     // 所以这里假设你有 `src/variables.sass` 这个文件
+      //     // 注意:在 sass-loader v8 中,这个选项名是 "prependData"
+      //     additionalData: `@import "~@/styles/variables.sass"`,
+      //   },
+      // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
+      // 因为 `scss` 语法在内部也是由 sass-loader 处理的
+      // 但是在配置 `prependData` 选项的时候
+      // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
+      // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
+      scss: {
+        additionalData: `@import "~@/styles/variables.scss";`,
+      },
+    },
+  },
+  pages: {
+    doc: {
+      entry: "src/sites/doc/main.ts",
+      template: "src/sites/doc/index.html",
+      filename: "index.html",
+      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
+      title: "NutUI",
+      // 在这个页面中包含的块,默认情况下会包含
+      // 提取出来的通用 chunk 和 vendor chunk。
+      chunks: ["chunk-vendors", "chunk-common", "doc"],
+    },
+    mobile: {
+      entry: "src/sites/mobile/main.ts",
+      template: "src/sites/mobile/index.html",
+      filename: "demo.html",
+      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
+      title: "NutUI",
+      // 在这个页面中包含的块,默认情况下会包含
+      // 提取出来的通用 chunk 和 vendor chunk。
+      chunks: ["chunk-vendors", "chunk-common", "mobile"],
+    },
+  },
+  configureWebpack: {
+    optimization: {
+      minimize: process.env.NODE_ENV === "production",
+      splitChunks: {
+        automaticNameDelimiter: "_",
+      },
+    },
+  },
+  chainWebpack: (config) => {
+    if (process.env.NODE_ENV === "production") {
+    }
+  },
+};