├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── __test__ └── index.test.js ├── circle.yml ├── example ├── App.vue └── index.js ├── package.json ├── postcss.config.js ├── src ├── Header │ ├── index.js │ └── style.module.css ├── index.js └── style.module.css └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) EGOIST <0x142857@gmail.com> (github.com/egoist) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-windows [![NPM version](https://img.shields.io/npm/v/vue-windows.svg?style=flat-square)](https://npmjs.com/package/vue-windows) [![NPM downloads](https://img.shields.io/npm/dm/vue-windows.svg?style=flat-square)](https://npmjs.com/package/vue-windows) [![Build Status](https://img.shields.io/circleci/project/egoist/vue-windows/master.svg?style=flat-square)](https://circleci.com/gh/egoist/vue-windows) 2 | 3 | It's inspired by the [socket.io](http://socket.io/) homepage, only 1kb. 4 | 5 | ## Install 6 | 7 | ```bash 8 | $ npm install --save vue-windows 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```vue 14 | 24 | 25 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ## API 41 | 42 | ### Props 43 | 44 | #### title 45 | 46 | - Type: `string` 47 | - Required: `true` 48 | 49 | #### shadow 50 | 51 | - Type: `boolean` 52 | - Default: `false` 53 | 54 | Whether to show window shadow. 55 | 56 | #### theme 57 | 58 | - Type: `string` 59 | - Default: `default` 60 | - Available: `default`, `dark` 61 | 62 | #### width 63 | 64 | - Type: `number`, `string` 65 | - Default: `100%` 66 | 67 | Number values are resolved into lengths in `px` while string values are used directly. 68 | 69 | #### height 70 | 71 | - Type: `number`, `string` 72 | - Default: `340` 73 | 74 | Number values are resolved into lengths in `px` while string values are used directly. 75 | 76 | ## Contributing 77 | 78 | 1. Fork it! 79 | 2. Create your feature branch: `git checkout -b my-new-feature` 80 | 3. Commit your changes: `git commit -am 'Add some feature'` 81 | 4. Push to the branch: `git push origin my-new-feature` 82 | 5. Submit a pull request :D 83 | 84 | ## Development 85 | 86 | ```bash 87 | yarn 88 | yarn example 89 | ``` 90 | 91 | ## License 92 | 93 | [MIT](https://egoist.mit-license.org/) © [EGOIST](https://github.com/egoist) 94 | -------------------------------------------------------------------------------- /__test__/index.test.js: -------------------------------------------------------------------------------- 1 | const fn = require('../') 2 | 3 | test('main', () => { 4 | expect(fn()).toBe(1) 5 | }) 6 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | 2 | version: 2 3 | jobs: 4 | build: 5 | working_directory: ~/repo 6 | docker: 7 | - image: circleci/node:latest 8 | branches: 9 | ignore: 10 | - gh-pages # list of branches to ignore 11 | - /release\/.*/ # or ignore regexes 12 | steps: 13 | - checkout 14 | - restore_cache: 15 | key: dependency-cache-{{ checksum "yarn.lock" }} 16 | - run: 17 | name: install dependences 18 | command: yarn 19 | - save_cache: 20 | key: dependency-cache-{{ checksum "yarn.lock" }} 21 | paths: 22 | - ./node_modules 23 | - run: 24 | name: test 25 | command: yarn test 26 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 114 | 115 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-windows", 3 | "version": "0.3.0", 4 | "description": "Vue component for making neat native-like window.", 5 | "license": "MIT", 6 | "repository": "egoist/vue-windows", 7 | "author": { 8 | "name": "EGOIST", 9 | "email": "0x142857@gmail.com", 10 | "url": "https://github.com/egoist" 11 | }, 12 | "scripts": { 13 | "test": "echo fine", 14 | "example": "poi --serve", 15 | "build": "bili --format cjs,umd,es --no-babel.babelrc --jsx vue", 16 | "build:example": "poi --prod", 17 | "prepublishOnly": "npm run build", 18 | "gh": "npm run build:example && gh-pages -d example/dist" 19 | }, 20 | "files": [ 21 | "dist" 22 | ], 23 | "main": "./dist/vue-windows.cjs.js", 24 | "module": "./dist/vue-windows.es.js", 25 | "cdn": "./dist/vue-windows.js", 26 | "jsdelivr": "./dist/vue-windows.js", 27 | "unpkg": "./dist/vue-windows.js", 28 | "keywords": [ 29 | "vue", 30 | "window", 31 | "mock" 32 | ], 33 | "devDependencies": { 34 | "bili": "^3.0.10", 35 | "gh-pages": "^0.11.0", 36 | "highlight.js": "^9.8.0", 37 | "poi": "^12.0.0", 38 | "postcss-cssnext": "^3.1.0", 39 | "vue": "^2.5.18", 40 | "vue-template-compiler": "^2.5.18" 41 | }, 42 | "poi": { 43 | "entry": "example/index.js", 44 | "output": { 45 | "dir": "example/dist" 46 | }, 47 | "babel": { 48 | "jsx": "vue" 49 | } 50 | }, 51 | "dependencies": { 52 | "nano-assign": "^1.0.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-cssnext')() 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/Header/index.js: -------------------------------------------------------------------------------- 1 | import style from './style.module.css' 2 | 3 | export default { 4 | functional: true, 5 | props: { 6 | title: { 7 | type: String, 8 | required: true 9 | }, 10 | isURL: { 11 | type: Boolean, 12 | default: false 13 | }, 14 | theme: { 15 | type: String 16 | } 17 | }, 18 | render(h, { props: { title, isURL, theme } }) { 19 | return ( 20 |
21 |
22 | 23 | 24 | 25 |
26 | 27 |
28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Header/style.module.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --red: #f85955; 3 | --dark-red: #d74246; 4 | --yellow: #fbbe3f; 5 | --dark-yellow: #d7a32d; 6 | --green: #45cc4b; 7 | --dark-green: #40ad36; 8 | } 9 | 10 | .header { 11 | height: 40px; 12 | padding-right: 75px; 13 | display: flex; 14 | align-items: center; 15 | } 16 | 17 | .title { 18 | flex: 1 1 320px; 19 | text-align: center; 20 | font-size: 12px; 21 | color: #766F79; 22 | white-space: nowrap; 23 | overflow: hidden; 24 | text-overflow: ellipsis; 25 | } 26 | 27 | .bullets { 28 | margin-left: 12px; 29 | display: flex; 30 | flex: 0 0; 31 | align-items: center; 32 | } 33 | 34 | .bullet { 35 | height: 12px; 36 | width: 12px; 37 | display: block; 38 | background: #ccc; 39 | border-radius: 100%; 40 | border: 1px solid; 41 | } 42 | 43 | .bullet + .bullet { 44 | margin-left: 5px; 45 | } 46 | 47 | .bullet-red { 48 | background: var(--red); 49 | border-color: var(--dark-red); 50 | } 51 | 52 | .bullet-yellow { 53 | background: var(--yellow); 54 | border-color: var(--dark-yellow); 55 | } 56 | 57 | .bullet-green { 58 | background: var(--green); 59 | border-color: var(--dark-green); 60 | } 61 | 62 | .header.isUrl { 63 | background: #e8e8e8; 64 | & .title { 65 | background: #fff; 66 | flex: 1 1 320px; 67 | border-radius: 4px; 68 | line-height: 26px; 69 | margin-left: 17px; 70 | padding: 0 12px; 71 | text-align: left; 72 | } 73 | } 74 | 75 | .header.dark { 76 | & .title { 77 | color: white; 78 | } 79 | 80 | & .bullet { 81 | border-color: transparent; 82 | } 83 | 84 | &.isUrl { 85 | background: rgba(255, 255, 255, .1); 86 | & .title { 87 | background-color: rgba(156, 156, 156, 0.21); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import assign from 'nano-assign' 2 | import styles from './style.module.css' 3 | import Header from './Header/index' 4 | 5 | const EditorWindow = { 6 | name: 'editor-window', 7 | props: { 8 | title: { 9 | required: true, 10 | type: String 11 | }, 12 | browser: Boolean, 13 | height: [Number, String], 14 | width: [Number, String], 15 | theme: { 16 | type: String, 17 | validator(v) { 18 | return ['default', 'dark'].indexOf(v) > -1 19 | } 20 | }, 21 | shadow: { 22 | type: Boolean, 23 | default: false 24 | } 25 | }, 26 | render(h) { 27 | const {browser, title, height, width, theme, shadow} = this.$props 28 | 29 | const className = [ 30 | styles.window, 31 | theme && styles[theme], 32 | shadow && styles.shadow 33 | ] 34 | 35 | const style = { 36 | height: Boolean(height) && (typeof height === 'number' ? `${height}px` : height), 37 | width: Boolean(width) && (typeof width === 'number' ? `${width}px` : width) 38 | } 39 | 40 | return h('div', { 41 | class: className, 42 | style 43 | }, [ 44 | h(Header, { 45 | props: { 46 | title, 47 | isURL: browser, 48 | theme 49 | } 50 | }), 51 | h('div', { 52 | class: styles.body 53 | }, this.$slots.default) 54 | ]) 55 | } 56 | } 57 | 58 | const BrowserWindow = { 59 | name: 'browser-window', 60 | props: EditorWindow.props, 61 | render(h) { 62 | const props = assign({ browser: true }, this.$props) 63 | 64 | if (props.title.substr(0, 8) === 'https://') { 65 | props.title = `https${props.title.substr(5)}` 66 | } 67 | 68 | return h(EditorWindow, { 69 | props 70 | }, this.$slots.default) 71 | } 72 | } 73 | 74 | export { 75 | EditorWindow, 76 | BrowserWindow 77 | } 78 | -------------------------------------------------------------------------------- /src/style.module.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --black: #151515; 3 | --green: #45cc4b; 4 | --dark-green: #40ad36; 5 | } 6 | 7 | .window { 8 | width: 100%; 9 | height: 340px; 10 | border-radius: 4px; 11 | text-align: left; 12 | vertical-align: top; 13 | display: inline-block; 14 | background-color: white; 15 | z-index: 1; 16 | overflow: hidden; 17 | border: 1px solid #ccc; 18 | } 19 | 20 | .body { 21 | padding: 10px 12px; 22 | position: relative; 23 | height: calc(100% - 40px); 24 | overflow: auto; 25 | } 26 | 27 | .shadow { 28 | box-shadow: rgba(0, 0, 0, 0.55) 0px 20px 68px; 29 | } 30 | 31 | .dark { 32 | color: white; 33 | border-color: var(--black); 34 | background-color: var(--black); 35 | } 36 | 37 | .safe { 38 | color: var(--dark-green); 39 | } 40 | 41 | .safe.dark { 42 | color: var(--green); 43 | background-color: transparent; 44 | } 45 | --------------------------------------------------------------------------------