Added Vue.js todo sample. (#106)
This commit is contained in:
parent
96c84a2c68
commit
d42b180100
|
@ -0,0 +1,25 @@
|
||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
|
||||||
|
[*]
|
||||||
|
|
||||||
|
# change these settings to your own preference
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# we recommend you to keep these unchanged
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[{package,bower}.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1 @@
|
||||||
|
* text=auto
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Build generated files
|
||||||
|
dist
|
||||||
|
lib
|
||||||
|
solution
|
||||||
|
temp
|
||||||
|
*.sppkg
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Visual Studio files
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
.vs
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
|
||||||
|
# Resx Generated Code
|
||||||
|
*.resx.ts
|
||||||
|
|
||||||
|
# Styles Generated Code
|
||||||
|
*.scss.ts
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Folders
|
||||||
|
.vscode
|
||||||
|
coverage
|
||||||
|
node_modules
|
||||||
|
sharepoint
|
||||||
|
src
|
||||||
|
temp
|
||||||
|
|
||||||
|
# Files
|
||||||
|
*.csproj
|
||||||
|
.git*
|
||||||
|
.yo-rc.json
|
||||||
|
gulpfile.js
|
||||||
|
tsconfig.json
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"vsicons.presets.angular": false,
|
||||||
|
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||||
|
"files.associations": {
|
||||||
|
"*.vue": "vue"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Todo Client Web Part built with Vue.js and Vue's single-file components
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Sample Todo web part demonstrating how you can utilize [Vue](https://vuejs.org/v2) (a progressive framework for building user interfaces) with SharePoint Framework using handy [single-file components](https://vuejs.org/v2/guide/single-file-components.html) approach.
|
||||||
|
|
||||||
|
## Used SharePoint Framework Version
|
||||||
|
![drop](https://img.shields.io/badge/drop-RC0-green.svg)
|
||||||
|
|
||||||
|
## Applies to
|
||||||
|
|
||||||
|
* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||||
|
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution|Author(s)
|
||||||
|
--------|---------
|
||||||
|
vuejs-todo-single-file-component|Sergei Sergeev ([@sergeev_srg](https://twitter.com/sergeev_srg))
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
Version|Date|Comments
|
||||||
|
-------|----|--------
|
||||||
|
0.0.1|January 27, 2017|Initial version.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Minimal Path to Awesome
|
||||||
|
|
||||||
|
- Clone this repo
|
||||||
|
- In the command line run:
|
||||||
|
- `npm i`
|
||||||
|
- `gulp serve`
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Demonstrates\uses below features:
|
||||||
|
|
||||||
|
- integration between third party frontend framework Vue.js and SharePoint Framework
|
||||||
|
- build pipeline customizations
|
||||||
|
- modern component-based architecture
|
||||||
|
- separation of concerns between markup, styling and code
|
||||||
|
- single-file components architecture for Vue.js
|
||||||
|
- custom webpack loaders
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"entry": "./lib/webparts/todo/TodoWebPart.js",
|
||||||
|
"manifest": "./src/webparts/todo/TodoWebPart.manifest.json",
|
||||||
|
"outputPath": "./dist/todo.bundle.js"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"externals": {
|
||||||
|
"vue": "node_modules/vue/dist/vue.runtime.js"
|
||||||
|
},
|
||||||
|
"localizedResources": {
|
||||||
|
"todoStrings": "webparts/todo/loc/{locale}.js"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"workingDir": "./temp/deploy/",
|
||||||
|
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||||
|
"container": "vue-todo",
|
||||||
|
"accessKey": "<!-- ACCESS KEY -->"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"solution": {
|
||||||
|
"name": "vue-todo-client-side-solution",
|
||||||
|
"id": "3a3be1f4-edfd-4816-8cfb-f100f1727031",
|
||||||
|
"version": "1.0.0.0"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"zippedPackage": "solution/vue-todo.sppkg"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"deployCdnPath": "temp/deploy"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"port": 4321,
|
||||||
|
"initialPage": "https://localhost:5432/workbench",
|
||||||
|
"https": true,
|
||||||
|
"api": {
|
||||||
|
"port": 5432,
|
||||||
|
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
// Display errors as warnings
|
||||||
|
"displayAsWarning": true,
|
||||||
|
// The TSLint task may have been configured with several custom lint rules
|
||||||
|
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
||||||
|
// project). If true, this flag will deactivate any of these rules.
|
||||||
|
"removeExistingRules": true,
|
||||||
|
// When true, the TSLint task is configured with some default TSLint "rules.":
|
||||||
|
"useDefaultConfigAsBase": false,
|
||||||
|
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
||||||
|
// which are active, other than the list of rules below.
|
||||||
|
"lintConfig": {
|
||||||
|
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
||||||
|
"rules": {
|
||||||
|
"class-name": false,
|
||||||
|
"export-name": false,
|
||||||
|
"forin": false,
|
||||||
|
"label-position": false,
|
||||||
|
"label-undefined": false,
|
||||||
|
"member-access": true,
|
||||||
|
"no-arg": false,
|
||||||
|
"no-console": false,
|
||||||
|
"no-construct": false,
|
||||||
|
"no-duplicate-case": true,
|
||||||
|
"no-duplicate-key": false,
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-eval": false,
|
||||||
|
"no-function-expression": true,
|
||||||
|
"no-internal-module": true,
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-unnecessary-semicolons": true,
|
||||||
|
"no-unused-expression": true,
|
||||||
|
"no-unused-imports": true,
|
||||||
|
"no-unused-variable": true,
|
||||||
|
"no-unreachable": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-with-statement": true,
|
||||||
|
"semicolon": true,
|
||||||
|
"trailing-comma": false,
|
||||||
|
"typedef": false,
|
||||||
|
"typedef-whitespace": false,
|
||||||
|
"use-named-parameter": true,
|
||||||
|
"valid-typeof": true,
|
||||||
|
"variable-name": false,
|
||||||
|
"whitespace": false,
|
||||||
|
"prefer-const": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const gulp = require('gulp');
|
||||||
|
const build = require('@microsoft/sp-build-web');
|
||||||
|
var merge = require('webpack-merge');
|
||||||
|
|
||||||
|
build.sass.setConfig({
|
||||||
|
sassMatch: []
|
||||||
|
});
|
||||||
|
|
||||||
|
build.configureWebpack.setConfig({
|
||||||
|
additionalConfiguration: function (config) {
|
||||||
|
var vueConfig = {
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
vue: {
|
||||||
|
esModule: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(config, vueConfig);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
build.copyStaticAssets.setConfig({
|
||||||
|
includeExtensions: ['vue', 'scss']
|
||||||
|
});
|
||||||
|
|
||||||
|
build.initialize(gulp);
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "vue-todo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@microsoft/sp-client-base": "~0.7.0",
|
||||||
|
"@microsoft/sp-client-preview": "~0.9.0",
|
||||||
|
"@microsoft/sp-core-library": "~0.1.2",
|
||||||
|
"@microsoft/sp-webpart-base": "~0.4.0",
|
||||||
|
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||||
|
"vue": "^2.1.10",
|
||||||
|
"vue-class-component": "^4.4.0",
|
||||||
|
"vue-property-decorator": "^3.4.0",
|
||||||
|
"vue-template-compiler": "^2.1.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/sp-build-web": "~0.9.0",
|
||||||
|
"@microsoft/sp-module-interfaces": "~0.7.0",
|
||||||
|
"@microsoft/sp-webpart-workbench": "~0.8.0",
|
||||||
|
"@types/chai": ">=3.4.34 <3.6.0",
|
||||||
|
"@types/mocha": ">=2.2.33 <2.6.0",
|
||||||
|
"gulp": "~3.9.1",
|
||||||
|
"node-sass": "^4.3.0",
|
||||||
|
"sass-loader": "^4.1.1",
|
||||||
|
"css-loader": "^0.26.1",
|
||||||
|
"vue-loader": "^10.0.2",
|
||||||
|
"webpack-merge": "^2.4.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp bundle",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"test": "gulp test"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
var context = require.context('.', true, /.+\.test\.js?$/);
|
||||||
|
|
||||||
|
context.keys().forEach(context);
|
||||||
|
|
||||||
|
module.exports = context;
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface ITodoWebPartProps {
|
||||||
|
message: string;
|
||||||
|
todos: string[];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||||
|
|
||||||
|
"id": "1c993233-909a-4662-8643-8548d961f2b3",
|
||||||
|
"alias": "TodoWebPart",
|
||||||
|
"componentType": "WebPart",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"manifestVersion": 2,
|
||||||
|
|
||||||
|
"preconfiguredEntries": [{
|
||||||
|
"groupId": "1c993233-909a-4662-8643-8548d961f2b3",
|
||||||
|
"group": { "default": "Under Development" },
|
||||||
|
"title": { "default": "Todo" },
|
||||||
|
"description": { "default": "My Todo's" },
|
||||||
|
"officeFabricIconFontName": "Page",
|
||||||
|
"properties": {
|
||||||
|
"message": "todos",
|
||||||
|
"todos": []
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { Version } from '@microsoft/sp-core-library';
|
||||||
|
import {
|
||||||
|
BaseClientSideWebPart,
|
||||||
|
IPropertyPaneConfiguration,
|
||||||
|
PropertyPaneTextField
|
||||||
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
|
import * as Vue from 'vue';
|
||||||
|
import TodoComponent from './components/todo/Todo.vue';
|
||||||
|
|
||||||
|
import * as strings from 'todoStrings';
|
||||||
|
import { ITodoWebPartProps } from './ITodoWebPartProps';
|
||||||
|
|
||||||
|
export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps> {
|
||||||
|
|
||||||
|
public data: ITodoWebPartProps;
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
this.domElement.innerHTML = `
|
||||||
|
<div id="app-${this.context.instanceId}">
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
this.data = {
|
||||||
|
message: this.properties.message,
|
||||||
|
todos: this.properties.todos
|
||||||
|
};
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
el: `#app-${this.context.instanceId}`,
|
||||||
|
render: h => h(TodoComponent, {
|
||||||
|
props: this.data
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onBeforeSerialize(): any {
|
||||||
|
this.properties.message = this.data.message;
|
||||||
|
this.properties.todos = this.data.todos;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get dataVersion(): Version {
|
||||||
|
return Version.parse('1.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||||
|
return {
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
description: strings.PropertyPaneDescription
|
||||||
|
},
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupName: strings.BasicGroupName,
|
||||||
|
groupFields: [
|
||||||
|
PropertyPaneTextField('message', {
|
||||||
|
label: strings.DescriptionFieldLabel
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
li {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import * as Vue from 'vue';
|
||||||
|
import { Component, Prop } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class TodoItem extends Vue {
|
||||||
|
@Prop
|
||||||
|
public todoText: string;
|
||||||
|
|
||||||
|
public onComplete(): void {
|
||||||
|
this.$emit('completed', this.todoText);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<template>
|
||||||
|
<li>
|
||||||
|
<div class="view">
|
||||||
|
<input type="checkbox" @click="onComplete">
|
||||||
|
<label>{{todoText}}</label>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
module.exports = require('./todoitem');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped src="./todoitem.scss" lang="sass"></style>
|
|
@ -0,0 +1,20 @@
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(175, 47, 47, 0.15);
|
||||||
|
font-size: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul{
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#new-todo {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 16px 16px 16px 16px;
|
||||||
|
border: 1px solid #d6d4d4;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import * as Vue from 'vue';
|
||||||
|
import { Component, Prop } from 'vue-property-decorator';
|
||||||
|
import TodoItem from '../todo-item/Todoitem.vue';
|
||||||
|
import { ITodoWebPartProps } from '../../ITodoWebPartProps';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
'todo-item': TodoItem
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Todo extends Vue implements ITodoWebPartProps {
|
||||||
|
@Prop
|
||||||
|
public message: string;
|
||||||
|
@Prop
|
||||||
|
public todos: string[];
|
||||||
|
|
||||||
|
public mytodos: string[] = this.todos;
|
||||||
|
public todoTitle: string = '';
|
||||||
|
|
||||||
|
public addTodo(): void {
|
||||||
|
if(!this.todoTitle){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mytodos.push(this.todoTitle);
|
||||||
|
this.todoTitle = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public completed(todo: string): void {
|
||||||
|
const index: number = this.mytodos.indexOf(todo, 0);
|
||||||
|
if (index > -1) {
|
||||||
|
this.mytodos.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>{{message}}</h1>
|
||||||
|
<div id="new-todo">
|
||||||
|
<input type="text" @keyup.enter="addTodo" v-model="todoTitle" placeholder="what needs to be done?">
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<todo-item v-for="(todo, index) in mytodos" :key="index + todo" :todoText="todo" v-on:completed="completed"></todo-item>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
module.exports = require('./todo');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped src="./todo.scss" lang="sass"></style>
|
|
@ -0,0 +1,7 @@
|
||||||
|
define([], function() {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "Todo web part settings",
|
||||||
|
"BasicGroupName": "Title",
|
||||||
|
"DescriptionFieldLabel": "Change the title"
|
||||||
|
}
|
||||||
|
});
|
10
samples/vuejs-todo-single-file-component/src/webparts/todo/loc/mystrings.d.ts
vendored
Normal file
10
samples/vuejs-todo-single-file-component/src/webparts/todo/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
declare interface ITodoStrings {
|
||||||
|
PropertyPaneDescription: string;
|
||||||
|
BasicGroupName: string;
|
||||||
|
DescriptionFieldLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'todoStrings' {
|
||||||
|
const strings: ITodoStrings;
|
||||||
|
export = strings;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
declare module "*.vue" {
|
||||||
|
import Vue = require('vue');
|
||||||
|
export default typeof Vue;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/// <reference types="mocha" />
|
||||||
|
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
describe('TodoWebPart', () => {
|
||||||
|
it('should do something', () => {
|
||||||
|
assert.ok(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"jsx": "react",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"types": [
|
||||||
|
"webpack-env"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue