├── .gitignore ├── LICENSE.md ├── README.md ├── csharp ├── GetImages │ └── run.csx ├── GetUploadUrl │ └── run.csx └── ResizeImage │ ├── project.json │ ├── run-module5.csx │ └── run.csx ├── javascript ├── GetImages │ └── index.js ├── GetUploadUrl │ └── index.js └── ResizeImage │ ├── index-module5.js │ └── index.js └── www ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── app ├── Api.js └── staticImages.js ├── assets └── README.md ├── components ├── AppLoader.vue ├── AppMasthead.vue ├── AppNavigation.vue ├── AppPhotogrid.vue ├── AppUpload.vue └── README.md ├── layouts ├── README.md └── default.vue ├── middleware └── README.md ├── nuxt.config.js ├── package-lock.json ├── package.json ├── pages ├── index.vue ├── loading.vue └── upload.vue ├── plugins └── README.md ├── static ├── README.md ├── auth.js ├── bk-gradient.jpg ├── corgi-space-bk.png ├── favicon.ico └── settings.sample.js ├── store └── README.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | *.DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two 7 | Icon 8 | # Thumbnails 9 | ._* 10 | # Files that might appear in the root of a volume 11 | .DocumentRevisions-V100 12 | .fseventsd 13 | .Spotlight-V100 14 | .TemporaryItems 15 | .Trashes 16 | .VolumeIcon.icns 17 | .com.apple.timemachine.donotpresent 18 | # Directories potentially created on remote AFP share 19 | .AppleDB 20 | .AppleDesktop 21 | Network Trash Folder 22 | Temporary Items 23 | .apdisk 24 | 25 | ### Node ### 26 | # Logs 27 | logs 28 | *.log 29 | npm-debug.log* 30 | 31 | # Runtime data 32 | pids 33 | *.pid 34 | *.seed 35 | *.pid.lock 36 | 37 | # Directory for instrumented libs generated by jscoverage/JSCover 38 | lib-cov 39 | 40 | # Coverage directory used by tools like istanbul 41 | coverage 42 | 43 | # nyc test coverage 44 | .nyc_output 45 | 46 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 47 | .grunt 48 | 49 | # node-waf configuration 50 | .lock-wscript 51 | 52 | # Compiled binary addons (http://nodejs.org/api/addons.html) 53 | build/Release 54 | 55 | # Dependency directories 56 | node_modules 57 | jspm_packages 58 | 59 | # Optional npm cache directory 60 | .npm 61 | 62 | # Optional eslint cache 63 | .eslintcache 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # Nuxt build 75 | .nuxt 76 | 77 | # Nuxt generate 78 | dist -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 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 all 13 | 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 THE 21 | SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | services: azure-functions, cosmos-db, storage, cognitive-services, active-directory 3 | platforms: nodejs, dotnet 4 | author: antchu 5 | --- 6 | 7 | # Build a serverless web app in Azure 8 | 9 | Code for [Build a serverless web app in Azure](https://docs.microsoft.com/en-us/azure/functions/tutorial-static-website-serverless-api-with-database?WT.mc_id=firstserverless-github-antchu) tutorial 10 | 11 | 12 | ## Web app installation 13 | 14 | ``` 15 | cd www 16 | npm install 17 | npm run generate 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /csharp/GetImages/run.csx: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | public static IEnumerable Run(HttpRequestMessage req, IEnumerable documents) 4 | { 5 | return documents; 6 | } 7 | -------------------------------------------------------------------------------- /csharp/GetUploadUrl/run.csx: -------------------------------------------------------------------------------- 1 | #r "Microsoft.WindowsAzure.Storage" 2 | using System.Net; 3 | using Microsoft.WindowsAzure.Storage; 4 | using Microsoft.WindowsAzure.Storage.Blob; 5 | 6 | public static async Task Run(HttpRequestMessage req, TraceWriter log) 7 | { 8 | var filename = req.GetQueryNameValuePairs() 9 | .FirstOrDefault(q => string.Compare(q.Key, "filename", true) == 0) 10 | .Value; 11 | 12 | CloudStorageAccount storageAccount = CloudStorageAccount.Parse( 13 | System.Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING", EnvironmentVariableTarget.Process)); 14 | var client = storageAccount.CreateCloudBlobClient(); 15 | var container = client.GetContainerReference("images"); 16 | await container.CreateIfNotExistsAsync(); 17 | 18 | CloudBlockBlob blob = container.GetBlockBlobReference(filename); 19 | 20 | SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy() 21 | { 22 | SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5), 23 | Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create 24 | }; 25 | 26 | var sasBlobToken = blob.GetSharedAccessSignature(adHocSAS); 27 | return new 28 | { 29 | url = blob.Uri + sasBlobToken 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /csharp/ResizeImage/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46": { 4 | "dependencies": { 5 | "ImageResizer": "4.1.11" 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /csharp/ResizeImage/run-module5.csx: -------------------------------------------------------------------------------- 1 | #r "Newtonsoft.Json" 2 | using ImageResizer; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Net.Http.Formatting; 6 | using Newtonsoft.Json; 7 | 8 | static HttpClient httpClient = new HttpClient(); 9 | 10 | public static async Task Run(Stream myBlob, string name, Stream thumbnail, TraceWriter log) 11 | { 12 | var instructions = new Instructions 13 | { 14 | Width = 200, 15 | Height = 200, 16 | Mode = FitMode.Crop, 17 | Scale = ScaleMode.Both 18 | };ImageBuilder.Current.Build(new ImageJob(myBlob, thumbnail, instructions) 19 | { 20 | DisposeSourceObject = false, 21 | ResetSourceStream = true 22 | }); 23 | 24 | var request = new HttpRequestMessage() { 25 | RequestUri = new Uri( 26 | System.Environment.GetEnvironmentVariable("COMP_VISION_URL", EnvironmentVariableTarget.Process) + 27 | "/analyze?visualFeatures=Description&language=en"), 28 | Method = HttpMethod.Post, 29 | Content = new StreamContent(myBlob) 30 | }; 31 | request.Headers.Add( 32 | "Ocp-Apim-Subscription-Key", 33 | System.Environment.GetEnvironmentVariable("COMP_VISION_KEY", EnvironmentVariableTarget.Process)); 34 | request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 35 | 36 | var response = await httpClient.SendAsync(request); 37 | dynamic result = await response.Content.ReadAsAsync(); 38 | 39 | return new { 40 | id = name, 41 | imgPath = "/images/" + name, 42 | thumbnailPath = "/thumbnails/" + name, 43 | description = result.description 44 | }; 45 | } -------------------------------------------------------------------------------- /csharp/ResizeImage/run.csx: -------------------------------------------------------------------------------- 1 | using ImageResizer; 2 | 3 | public static void Run(Stream myBlob, string name, Stream thumbnail, TraceWriter log) 4 | { 5 | var instructions = new Instructions 6 | { 7 | Width = 200, 8 | Height = 200, 9 | Mode = FitMode.Crop, 10 | Scale = ScaleMode.Both 11 | }; 12 | 13 | ImageBuilder.Current.Build(new ImageJob(myBlob, thumbnail, instructions)); 14 | } 15 | -------------------------------------------------------------------------------- /javascript/GetImages/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (context, req, documents) { 2 | context.res = documents; 3 | context.done(); 4 | }; -------------------------------------------------------------------------------- /javascript/GetUploadUrl/index.js: -------------------------------------------------------------------------------- 1 | const azure = require('azure-storage'); 2 | 3 | module.exports = function (context, req) { 4 | const filename = req.query.filename; 5 | const container = 'images'; 6 | 7 | const blobService = azure.createBlobService(); 8 | 9 | const currentDate = new Date(); 10 | const startDate = new Date(currentDate.getTime() - 60 * 1000); 11 | const expiryDate = new Date(currentDate.getTime() + 5 * 60 * 1000); 12 | 13 | const permissions = 14 | azure.BlobUtilities.SharedAccessPermissions.READ + 15 | azure.BlobUtilities.SharedAccessPermissions.WRITE + 16 | azure.BlobUtilities.SharedAccessPermissions.CREATE; 17 | 18 | const sharedAccessPolicy = { 19 | AccessPolicy: { 20 | Permissions: permissions, 21 | Start: startDate, 22 | Expiry: expiryDate 23 | } 24 | }; 25 | 26 | const sasToken = blobService.generateSharedAccessSignature(container, filename, sharedAccessPolicy); 27 | 28 | context.res = { 29 | status: 200, body: 30 | { 31 | url: blobService.getUrl(container, filename, sasToken) 32 | } 33 | }; 34 | context.done(); 35 | }; 36 | -------------------------------------------------------------------------------- /javascript/ResizeImage/index-module5.js: -------------------------------------------------------------------------------- 1 | const Jimp = require("jimp"); 2 | const axios = require('axios'); 3 | 4 | module.exports = function (context, myBlob) { 5 | context.log("JavaScript blob trigger function processed blob \n Name:", context.bindingData.name, "\n Blob Size:", myBlob.length, "Bytes"); 6 | Jimp.read(myBlob).then(image => { 7 | image 8 | .cover(200, 200) 9 | .quality(60) 10 | .getBuffer(Jimp.MIME_JPEG, (error, stream) => { 11 | if (error) { 12 | context.done(error); 13 | } else { 14 | context.log('calling cog svc'); 15 | axios.post(process.env.COMP_VISION_URL + '/analyze?visualFeatures=Description&language=en', myBlob, { 16 | headers: { 17 | 'Ocp-Apim-Subscription-Key': process.env.COMP_VISION_KEY, 18 | 'Content-Type': 'application/octet-stream' 19 | } 20 | }).then(response => { 21 | context.log(JSON.stringify(response.data, null, 2)); 22 | context.bindings.thumbnail = stream; 23 | context.done(null, { 24 | id: context.bindingData.name, 25 | imgPath: "/images/" + context.bindingData.name, 26 | thumbnailPath: "/thumbnails/" + context.bindingData.name, 27 | description: response.data.description 28 | }); 29 | }).catch(err => { 30 | context.log(JSON.stringify(err)); 31 | context.done(err); 32 | }); 33 | 34 | } 35 | }); 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /javascript/ResizeImage/index.js: -------------------------------------------------------------------------------- 1 | const Jimp = require("jimp"); 2 | 3 | module.exports = function (context, myBlob) { 4 | context.log("JavaScript blob trigger function processed blob \n Name:", context.bindingData.name, "\n Blob Size:", myBlob.length, "Bytes"); 5 | Jimp.read(myBlob).then(image => { 6 | image 7 | .cover(200, 200) 8 | .quality(60) 9 | .getBuffer(Jimp.MIME_JPEG, (error, stream) => { 10 | if (error) { 11 | context.done(error); 12 | } else { 13 | context.bindings.thumbnail = stream; 14 | context.done(null, { 15 | id: context.bindingData.name, 16 | imgPath: "/images/" + context.bindingData.name, 17 | thumbnailPath: "/thumbnails/" + context.bindingData.name 18 | }); 19 | } 20 | }); 21 | }); 22 | }; -------------------------------------------------------------------------------- /www/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /www/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 13 | 'plugin:vue/essential', 14 | ], 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'vue' 18 | ], 19 | // add your custom rules here 20 | rules: {} 21 | } 22 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | *.DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two 7 | Icon 8 | # Thumbnails 9 | ._* 10 | # Files that might appear in the root of a volume 11 | .DocumentRevisions-V100 12 | .fseventsd 13 | .Spotlight-V100 14 | .TemporaryItems 15 | .Trashes 16 | .VolumeIcon.icns 17 | .com.apple.timemachine.donotpresent 18 | # Directories potentially created on remote AFP share 19 | .AppleDB 20 | .AppleDesktop 21 | Network Trash Folder 22 | Temporary Items 23 | .apdisk 24 | 25 | ### Node ### 26 | # Logs 27 | logs 28 | *.log 29 | npm-debug.log* 30 | 31 | # Runtime data 32 | pids 33 | *.pid 34 | *.seed 35 | *.pid.lock 36 | 37 | # Directory for instrumented libs generated by jscoverage/JSCover 38 | lib-cov 39 | 40 | # Coverage directory used by tools like istanbul 41 | coverage 42 | 43 | # nyc test coverage 44 | .nyc_output 45 | 46 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 47 | .grunt 48 | 49 | # node-waf configuration 50 | .lock-wscript 51 | 52 | # Compiled binary addons (http://nodejs.org/api/addons.html) 53 | build/Release 54 | 55 | # Dependency directories 56 | node_modules 57 | jspm_packages 58 | 59 | # Optional npm cache directory 60 | .npm 61 | 62 | # Optional eslint cache 63 | .eslintcache 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # Nuxt build 75 | .nuxt 76 | 77 | # Nuxt generate 78 | dist -------------------------------------------------------------------------------- /www/README.md: -------------------------------------------------------------------------------- 1 | # first-serverless 2 | 3 | > Build your first serverless web app 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | $ npm install # Or yarn install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ npm run dev 13 | 14 | # build for production and launch server 15 | $ npm run build 16 | $ npm start 17 | 18 | # generate static project 19 | $ npm run generate 20 | ``` 21 | 22 | For detailed explanation on how things work, checkout the [Nuxt.js docs](https://github.com/nuxt/nuxt.js). 23 | -------------------------------------------------------------------------------- /www/app/Api.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | class Api { 4 | constructor(baseUrl, authToken, blobBaseUrl) { 5 | this.baseUrl = baseUrl 6 | this.authToken = authToken 7 | this.blobBaseUrl = blobBaseUrl 8 | } 9 | 10 | getImages() { 11 | const config = { 12 | headers: { 13 | 'X-ZUMO-AUTH': this.authToken 14 | } 15 | } 16 | return axios.get(`${this.baseUrl}/api/GetImages`, config) 17 | .then(response => { 18 | if (response.status === 200) { 19 | return response.data.map(i => { 20 | if (this.blobBaseUrl) { 21 | i.imagePath = this.blobBaseUrl + i.imagePath 22 | i.thumbnailPath = this.blobBaseUrl + i.thumbnailPath 23 | } 24 | return i 25 | }) 26 | } else { 27 | throw response.data 28 | } 29 | }) 30 | } 31 | 32 | uploadImage(file, uploadProgressCallback) { 33 | return this._getUploadSasUri(file.name) 34 | .then(sasUrl => this._uploadBlob(sasUrl, file, uploadProgressCallback)) 35 | .then(() => this._waitForFile(file.name)) 36 | } 37 | 38 | getUsername() { 39 | const config = { 40 | headers: { 41 | 'X-ZUMO-AUTH': this.authToken 42 | } 43 | } 44 | return axios.get(`${this.baseUrl}/.auth/me`, config) 45 | .then(response => { 46 | const userDetails = response.data[0] 47 | const userFirstName = userDetails.user_claims.find(function (i) { return i.typ === 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname' }); 48 | return userFirstName ? userFirstName.val : null 49 | }); 50 | } 51 | 52 | _getUploadSasUri(filename) { 53 | const config = { 54 | headers: { 55 | 'X-ZUMO-AUTH': this.authToken 56 | }, 57 | params: { 58 | filename 59 | } 60 | } 61 | return axios.get(`${this.baseUrl}/api/GetUploadUrl`, config) 62 | .then(response => response.data.url) 63 | } 64 | 65 | _uploadBlob(sasUrl, file, uploadProgressCallback) { 66 | const config = { 67 | headers: { 68 | 'Content-Type': 'application/octet-stream', 69 | 'x-ms-version': '2017-04-17', 70 | 'x-ms-blob-type': 'BlockBlob', 71 | 'x-ms-blob-content-type': file.type 72 | }, 73 | onUploadProgress(e) { 74 | if (e.lengthComputable) { 75 | uploadProgressCallback(e.loaded / e.total * 100) 76 | } else { 77 | uploadProgressCallback(0) 78 | } 79 | } 80 | } 81 | return axios.put(sasUrl, file, config) 82 | .then(() => sasUrl) 83 | } 84 | 85 | _waitForFile(filename) { 86 | return new Promise(resolve => { 87 | setTimeout(() => { 88 | this.getImages() 89 | .then(images => { 90 | if (images.some(i => i.id === filename)) { 91 | resolve(filename) 92 | } else { 93 | resolve(this._waitForFile(filename)) 94 | } 95 | }) 96 | }, 500); 97 | }) 98 | } 99 | } 100 | 101 | 102 | 103 | export default Api 104 | -------------------------------------------------------------------------------- /www/app/staticImages.js: -------------------------------------------------------------------------------- 1 | export default function() { 2 | return [] 3 | // return Array(15).fill().map((_, i) => { 4 | // return { 5 | // id: i + 1, 6 | // imgPath: '', 7 | // thumbnailPath: 'https://lorempixel.com/200/200/cats/?' + i, 8 | // description: { 9 | // captions: [ 10 | // { text: '' } 11 | // ] 12 | // } 13 | // } 14 | // }) 15 | } 16 | -------------------------------------------------------------------------------- /www/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/assets#webpacked 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /www/components/AppLoader.vue: -------------------------------------------------------------------------------- 1 | 106 | 107 | 191 | 192 | 218 | -------------------------------------------------------------------------------- /www/components/AppMasthead.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /www/components/AppNavigation.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | 33 | 54 | -------------------------------------------------------------------------------- /www/components/AppPhotogrid.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 62 | 63 | 209 | -------------------------------------------------------------------------------- /www/components/AppUpload.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 59 | 60 | 88 | -------------------------------------------------------------------------------- /www/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | The components directory contains your Vue.js Components. 4 | Nuxt.js doesn't supercharge these components. 5 | 6 | **This directory is not required, you can delete it if you don't want to use it.** 7 | -------------------------------------------------------------------------------- /www/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | This directory contains your Application Layouts. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/views#layouts 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /www/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 9 | 10 | 80 | -------------------------------------------------------------------------------- /www/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | This directory contains your Application Middleware. 4 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing#middleware 8 | 9 | **This directory is not required, you can delete it if you don't want to use it.** 10 | -------------------------------------------------------------------------------- /www/nuxt.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /* 3 | ** Headers of the page 4 | */ 5 | head: { 6 | title: 'first-serverless', 7 | meta: [ 8 | { charset: 'utf-8' }, 9 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 10 | { hid: 'description', name: 'description', content: 'Build your first serverless web app' } 11 | ], 12 | link: [ 13 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } 14 | ], 15 | script: [ 16 | { src: '/settings.js' }, 17 | { src: '/auth.js' } 18 | ] 19 | }, 20 | /* 21 | ** Customize the progress bar color 22 | */ 23 | loading: { color: '#3B8070' }, 24 | /* 25 | ** Build configuration 26 | */ 27 | build: { 28 | /* 29 | ** Run ESLint on save 30 | */ 31 | extend (config, { isDev, isClient }) { 32 | if (isDev && isClient) { 33 | config.module.rules.push({ 34 | enforce: 'pre', 35 | test: /\.(js|vue)$/, 36 | loader: 'eslint-loader', 37 | exclude: /(node_modules)/ 38 | }) 39 | } 40 | }, 41 | publicPath: '/nuxt/', 42 | subFolders: false 43 | }, 44 | router: { 45 | mode: 'hash' 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /www/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-serverless", 3 | "version": "1.0.0", 4 | "description": "Build your first serverless web app", 5 | "author": "sdras ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate --spa", 12 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", 13 | "precommit": "npm run lint" 14 | }, 15 | "dependencies": { 16 | "axios": "^0.17.1", 17 | "gsap": "^1.20.3", 18 | "nuxt": "^1.4.2" 19 | }, 20 | "devDependencies": { 21 | "babel-eslint": "^8.2.1", 22 | "eslint": "^4.15.0", 23 | "eslint-friendly-formatter": "^3.0.0", 24 | "eslint-loader": "^1.7.1", 25 | "eslint-plugin-vue": "^4.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /www/pages/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 123 | 124 | 138 | -------------------------------------------------------------------------------- /www/pages/loading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /www/pages/upload.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | 22 | 37 | -------------------------------------------------------------------------------- /www/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | This directory contains your Javascript plugins that you want to run before instantiating the root vue.js application. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/plugins 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /www/static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt. 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /www/static/auth.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | let authToken = "" 3 | 4 | if (window.location.hash) { 5 | const match = window.location.hash.match(/token=([^&]+)/) 6 | if (match && match[1]) { 7 | authToken = JSON.parse(decodeURIComponent(match[1])).authenticationToken 8 | sessionStorage.setItem('authToken', authToken) 9 | history.pushState("", document.title, window.location.pathname + window.location.search) 10 | } 11 | } 12 | 13 | if (!authToken) { 14 | authToken = sessionStorage.getItem('authToken') 15 | } 16 | 17 | window.auth = { 18 | token: authToken, 19 | loginUrl: window.apiBaseUrl + 20 | '/.auth/login/aad?session_mode=token&post_login_redirect_url=' + 21 | encodeURIComponent(window.location.href), 22 | logout: function() { 23 | sessionStorage.removeItem('authToken') 24 | window.location.reload() 25 | } 26 | } 27 | }()) 28 | -------------------------------------------------------------------------------- /www/static/bk-gradient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/functions-first-serverless-web-application/374b0a1ba53f07755cc62fe3b9e1aea1bdd161ea/www/static/bk-gradient.jpg -------------------------------------------------------------------------------- /www/static/corgi-space-bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/functions-first-serverless-web-application/374b0a1ba53f07755cc62fe3b9e1aea1bdd161ea/www/static/corgi-space-bk.png -------------------------------------------------------------------------------- /www/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/functions-first-serverless-web-application/374b0a1ba53f07755cc62fe3b9e1aea1bdd161ea/www/static/favicon.ico -------------------------------------------------------------------------------- /www/static/settings.sample.js: -------------------------------------------------------------------------------- 1 | window.apiBaseUrl = '' 2 | window.blobBaseUrl = '' 3 | window.authEnabled = false 4 | -------------------------------------------------------------------------------- /www/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | This directory contains your Vuex Store files. 4 | Vuex Store option is implemented in the Nuxt.js framework. 5 | Creating a index.js file in this directory activate the option in the framework automatically. 6 | 7 | More information about the usage of this directory in the documentation: 8 | https://nuxtjs.org/guide/vuex-store 9 | 10 | **This directory is not required, you can delete it if you don't want to use it.** 11 | --------------------------------------------------------------------------------