From eca13b833d3579d36956d2093bf31a09b9c75beb Mon Sep 17 00:00:00 2001
From: Your Name <123456>
Date: 星期三, 29 六月 2022 09:22:09 +0800
Subject: [PATCH] Merge branch 'master' of https://sinanoaq.cn:8888/r/gtqt

---
 src/assets/menu/card5.png                      |    0 
 src/assets/menu/icon4.png                      |    0 
 src/assets/menu/icon5.png                      |    0 
 src/assets/loginPage/login_icon_user.png       |    0 
 src/assets/menu/icon11.png                     |    0 
 src/assets/menu/icon9.png                      |    0 
 static/loginPage.js/login.js                   | 1545 +++++++++++++++++++++++++++++++++++++++
 src/assets/menu/bg_home.jpg                    |    0 
 src/assets/menu/icon1.png                      |    0 
 src/views/loginPage/loginPage.vue              |  160 ++++
 src/assets/menu/icon6.png                      |    0 
 src/assets/menu/card1.png                      |    0 
 src/assets/menu/card4.png                      |    0 
 static/loginPage.js/loginApp.js                |  137 +++
 src/assets/menu/card9.png                      |    0 
 src/views/loginPage/component/accountLogin.vue |  211 +++++
 src/assets/menu/admin.png                      |    0 
 src/assets/menu/icon2.png                      |    0 
 src/assets/menu/icon7.png                      |    0 
 src/assets/menu/card7.png                      |    0 
 src/assets/menu/card2.png                      |    0 
 src/assets/menu/card8.png                      |    0 
 src/assets/menu/card6.png                      |    0 
 src/assets/menu/icon8.png                      |    0 
 src/assets/menu/card11.png                     |    0 
 src/assets/menu/icon3.png                      |    0 
 src/assets/menu/card3.png                      |    0 
 src/assets/menu/card10.png                     |    0 
 src/assets/menu/icon10.png                     |    0 
 src/assets/loginPage/login_icon_password.png   |    0 
 src/views/menu/menu.vue                        |  250 ++++++
 31 files changed, 2,303 insertions(+), 0 deletions(-)

diff --git a/src/assets/loginPage/login_icon_password.png b/src/assets/loginPage/login_icon_password.png
new file mode 100644
index 0000000..1f6653d
--- /dev/null
+++ b/src/assets/loginPage/login_icon_password.png
Binary files differ
diff --git a/src/assets/loginPage/login_icon_user.png b/src/assets/loginPage/login_icon_user.png
new file mode 100644
index 0000000..a113a9b
--- /dev/null
+++ b/src/assets/loginPage/login_icon_user.png
Binary files differ
diff --git a/src/assets/menu/admin.png b/src/assets/menu/admin.png
new file mode 100644
index 0000000..55eeace
--- /dev/null
+++ b/src/assets/menu/admin.png
Binary files differ
diff --git a/src/assets/menu/bg_home.jpg b/src/assets/menu/bg_home.jpg
new file mode 100644
index 0000000..ab60219
--- /dev/null
+++ b/src/assets/menu/bg_home.jpg
Binary files differ
diff --git a/src/assets/menu/card1.png b/src/assets/menu/card1.png
new file mode 100644
index 0000000..d70d653
--- /dev/null
+++ b/src/assets/menu/card1.png
Binary files differ
diff --git a/src/assets/menu/card10.png b/src/assets/menu/card10.png
new file mode 100644
index 0000000..cb8129f
--- /dev/null
+++ b/src/assets/menu/card10.png
Binary files differ
diff --git a/src/assets/menu/card11.png b/src/assets/menu/card11.png
new file mode 100644
index 0000000..2155f53
--- /dev/null
+++ b/src/assets/menu/card11.png
Binary files differ
diff --git a/src/assets/menu/card2.png b/src/assets/menu/card2.png
new file mode 100644
index 0000000..9415cb6
--- /dev/null
+++ b/src/assets/menu/card2.png
Binary files differ
diff --git a/src/assets/menu/card3.png b/src/assets/menu/card3.png
new file mode 100644
index 0000000..b22eae4
--- /dev/null
+++ b/src/assets/menu/card3.png
Binary files differ
diff --git a/src/assets/menu/card4.png b/src/assets/menu/card4.png
new file mode 100644
index 0000000..d29a9f4
--- /dev/null
+++ b/src/assets/menu/card4.png
Binary files differ
diff --git a/src/assets/menu/card5.png b/src/assets/menu/card5.png
new file mode 100644
index 0000000..ee12eb6
--- /dev/null
+++ b/src/assets/menu/card5.png
Binary files differ
diff --git a/src/assets/menu/card6.png b/src/assets/menu/card6.png
new file mode 100644
index 0000000..cc7d602
--- /dev/null
+++ b/src/assets/menu/card6.png
Binary files differ
diff --git a/src/assets/menu/card7.png b/src/assets/menu/card7.png
new file mode 100644
index 0000000..d5bf656
--- /dev/null
+++ b/src/assets/menu/card7.png
Binary files differ
diff --git a/src/assets/menu/card8.png b/src/assets/menu/card8.png
new file mode 100644
index 0000000..a839c27
--- /dev/null
+++ b/src/assets/menu/card8.png
Binary files differ
diff --git a/src/assets/menu/card9.png b/src/assets/menu/card9.png
new file mode 100644
index 0000000..7481ef0
--- /dev/null
+++ b/src/assets/menu/card9.png
Binary files differ
diff --git a/src/assets/menu/icon1.png b/src/assets/menu/icon1.png
new file mode 100644
index 0000000..bef5341
--- /dev/null
+++ b/src/assets/menu/icon1.png
Binary files differ
diff --git a/src/assets/menu/icon10.png b/src/assets/menu/icon10.png
new file mode 100644
index 0000000..0f1d961
--- /dev/null
+++ b/src/assets/menu/icon10.png
Binary files differ
diff --git a/src/assets/menu/icon11.png b/src/assets/menu/icon11.png
new file mode 100644
index 0000000..392b926
--- /dev/null
+++ b/src/assets/menu/icon11.png
Binary files differ
diff --git a/src/assets/menu/icon2.png b/src/assets/menu/icon2.png
new file mode 100644
index 0000000..5ca9d63
--- /dev/null
+++ b/src/assets/menu/icon2.png
Binary files differ
diff --git a/src/assets/menu/icon3.png b/src/assets/menu/icon3.png
new file mode 100644
index 0000000..c512b58
--- /dev/null
+++ b/src/assets/menu/icon3.png
Binary files differ
diff --git a/src/assets/menu/icon4.png b/src/assets/menu/icon4.png
new file mode 100644
index 0000000..1088209
--- /dev/null
+++ b/src/assets/menu/icon4.png
Binary files differ
diff --git a/src/assets/menu/icon5.png b/src/assets/menu/icon5.png
new file mode 100644
index 0000000..28200e7
--- /dev/null
+++ b/src/assets/menu/icon5.png
Binary files differ
diff --git a/src/assets/menu/icon6.png b/src/assets/menu/icon6.png
new file mode 100644
index 0000000..c58c489
--- /dev/null
+++ b/src/assets/menu/icon6.png
Binary files differ
diff --git a/src/assets/menu/icon7.png b/src/assets/menu/icon7.png
new file mode 100644
index 0000000..838cb9a
--- /dev/null
+++ b/src/assets/menu/icon7.png
Binary files differ
diff --git a/src/assets/menu/icon8.png b/src/assets/menu/icon8.png
new file mode 100644
index 0000000..0e7d42f
--- /dev/null
+++ b/src/assets/menu/icon8.png
Binary files differ
diff --git a/src/assets/menu/icon9.png b/src/assets/menu/icon9.png
new file mode 100644
index 0000000..ce58f60
--- /dev/null
+++ b/src/assets/menu/icon9.png
Binary files differ
diff --git a/src/views/loginPage/component/accountLogin.vue b/src/views/loginPage/component/accountLogin.vue
new file mode 100644
index 0000000..d5569a4
--- /dev/null
+++ b/src/views/loginPage/component/accountLogin.vue
@@ -0,0 +1,211 @@
+<template>
+	<el-form size="large" class="login-content-form">
+		<el-form-item class="login-animation1">
+			<el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.username" clearable autocomplete="off" size="large">
+				<template #prefix>
+					<el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_user.png" style="width: 24px;height: 24px"></el-icon>
+				</template>
+			</el-input>
+		</el-form-item>
+		<el-form-item class="login-animation2">
+			<el-input
+				:type="isShowPassword ? 'text' : 'password'"
+				:placeholder="$t('message.account.accountPlaceholder2')"
+				v-model="ruleForm.password"
+				autocomplete="off"
+				size="large"
+			>
+				<template #prefix>
+					<el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_password.png" style="width: 24px;height: 24px"></el-icon>
+				</template>
+				<template #suffix>
+					<i
+						class="iconfont el-input__icon login-content-password"
+						:class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
+						@click="isShowPassword = !isShowPassword"
+					>
+					</i>
+				</template>
+			</el-input>
+		</el-form-item>
+		<el-form-item class="login-animation4 codeDeal">
+			<el-checkbox v-model="saveCode" label="记住密码" size="large" />
+			<span class="forgetCode">忘记密码?</span>
+		</el-form-item>
+		<el-form-item class="login-animation4">
+			<el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="loading.signIn">
+				<span>登录系统</span>
+			</el-button>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive, defineComponent, computed } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import { useI18n } from 'vue-i18n';
+import Cookies from 'js-cookie';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { initFrontEndControlRoutes } from '/@/router/frontEnd';
+import { initBackEndControlRoutes } from '/@/router/backEnd';
+import { Session } from '/@/utils/storage';
+import { formatAxis } from '/@/utils/formatTime';
+import { NextLoading } from '/@/utils/loading';
+import { useLoginApi } from '/@/api/login';
+import {useUserInfo} from "/@/stores/userInfo";
+
+export default defineComponent({
+	name: 'accountLogin',
+	setup() {
+		const { t } = useI18n();
+		const userInfo = useUserInfo()
+		const { userInfos } = storeToRefs(userInfo);
+		const storesThemeConfig = useThemeConfig();
+		const { themeConfig } = storeToRefs(storesThemeConfig);
+		const route = useRoute();
+		const router = useRouter();
+		const state = reactive({
+			isShowPassword: false,
+			ruleForm: {
+				username: 'admin',
+				password: '123456',
+			},
+			loading: {
+				signIn: false,
+			},
+		});
+		// 时间获取
+		const currentTime = computed(() => {
+			return formatAxis(new Date());
+		});
+		// 登录
+		const onSignIn = async () => {
+			state.loading.signIn = true;
+			// 存储 token 到浏览器缓存
+			let res = await useLoginApi().signIn(state.ruleForm)
+			if(res.data.code === '200'){
+				Session.set('ifMenu',false)
+				Session.set('projectId','')
+				Session.set('token', res.data.data.accessToken);
+				Session.set('sign',res.data.data.id)
+				await initFrontEndControlRoutes();
+				signInSuccess();
+			}else{
+				state.loading.signIn = false
+				ElMessage({
+					type:'warning',
+					message:res.data.msg
+				})
+			}
+			// Session.set('token', Math.random().toString(36).substr(0));
+			// // 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
+			// Cookies.set('userName', state.ruleForm.username);
+			// if (!themeConfig.value.isRequestRoutes) {
+			// 	// 前端控制路由,2、请注意执行顺序
+			// 	await initFrontEndControlRoutes();
+			// 	signInSuccess();
+			// } else {
+			// 	// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
+			// 	// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
+			// 	await initBackEndControlRoutes();
+			// 	// 执行完 initBackEndControlRoutes,再执行 signInSuccess
+			// 	signInSuccess();
+			// }
+		};
+		// 登录成功后的跳转
+		const signInSuccess = async () => {
+			// 初始化登录成功时间问候语
+			let currentTimeInfo = currentTime.value;
+			// 登录成功,跳到转首页
+			// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
+			if (route.query?.redirect) {
+				router.push('/menu');
+				// router.push({
+				// 	path: <string>route.query?.redirect,
+				// 	query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
+				// });
+			} else {
+				router.push('/login');
+			}
+			state.loading.signIn = true;
+			const signInText = t('message.signInText');
+			ElMessage.success(`${currentTimeInfo},${signInText}`);
+			// 登录成功提示
+			// 关闭 loading
+			// 添加 loading,防止第一次进入界面时出现短暂空白
+			// NextLoading.start();
+		};
+		return {
+			onSignIn,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped lang="scss">
+.login-content-form {
+	margin-top: 40px;
+	width: 420px;
+
+	.el-input::v-deep .el-input__wrapper{
+		height: 56px;
+		border-radius: 28px;
+		padding: 0 30px;
+		background: #F2F2F2;
+		&:focus-within{
+			border: 1px solid #2053D7;
+		}
+	}
+	@for $i from 1 through 4 {
+		.login-animation#{$i} {
+			opacity: 0;
+			animation-name: error-num;
+			animation-duration: 0.5s;
+			animation-fill-mode: forwards;
+			animation-delay: calc($i/10) + s;
+		}
+	}
+	.codeDeal::v-deep .el-form-item__content{
+		display: flex;
+		justify-content: space-between;
+
+		.forgetCode{
+			color: #2053D7;
+			cursor: pointer;
+		}
+	}
+	.login-content-password {
+		width: 100%;
+		display: inline-block;
+		width: 20px;
+		cursor: pointer;
+		&:hover {
+			color: #909399;
+		}
+	}
+	.login-content-code {
+		width: 100%;
+		padding: 0;
+		font-weight: bold;
+		letter-spacing: 5px;
+	}
+	.login-content-submit {
+		width: 100%;
+		height: 56px;
+		font-size: 16px;
+		border-radius: 28px;
+		letter-spacing: 4px;
+		font-weight: 300;
+		margin-top: 15px;
+		background: #2053D7;
+		transition: .3s;
+		&:hover{
+			letter-spacing: 6px;
+			background: #4E7AEC;
+		}
+	}
+}
+</style>
diff --git a/src/views/loginPage/loginPage.vue b/src/views/loginPage/loginPage.vue
new file mode 100644
index 0000000..66c68bc
--- /dev/null
+++ b/src/views/loginPage/loginPage.vue
@@ -0,0 +1,160 @@
+<template>
+	<div class="login-container">
+		<div id="particles-js" style="display: flex;align-items: center;justify-content: center">
+			<canvas class="particles-js-canvas-el" style="width: 100%; height: 100%;" width="472" height="625"></canvas>
+		</div>
+		<div class="loginContent">
+			<div class="loginContL">
+				<div class="apTitleT">新疆国泰新华</div>
+				<div class="apTitleB">安全风险预警监测系统</div>
+				<span></span>
+			</div>
+			<div class="loginPanel">
+				<div class="welc">WELCOME!</div>
+				<div class="welcc">欢迎登录</div>
+<!--				<div class="loginInfo">-->
+<!--					<el-input v-model="input" placeholder="Please input" />-->
+<!--				</div>-->
+				<div>
+					<el-tabs v-model="tabsActiveName">
+						<AccountLogin />
+					</el-tabs>
+				</div>
+			</div>
+		</div>
+
+	</div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive, computed, defineComponent, onMounted } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import logoMini from '/@/assets/logo-mini.svg';
+import loginIconTwo from '/@/assets/login-icon-two.svg';
+import { NextLoading } from '/@/utils/loading';
+import AccountLogin from '/@/views/loginPage/component/accountLogin.vue';
+import { loginBg } from '../../../static/loginPage.js/login.js'
+import { loginApp } from '../../../static/loginPage.js/loginApp.js'
+
+// 定义接口来定义对象的类型
+interface LoginState {
+	tabsActiveName: string;
+	isScan: boolean;
+}
+
+export default defineComponent({
+	name: 'loginIndex',
+	components: { AccountLogin },
+	setup() {
+		const storesThemeConfig = useThemeConfig();
+		const { themeConfig } = storeToRefs(storesThemeConfig);
+		const state = reactive<LoginState>({
+			tabsActiveName: 'account',
+			isScan: false,
+		});
+		// 获取布局配置信息
+		const getThemeConfig = computed(() => {
+			return themeConfig.value;
+		});
+		// 页面加载时
+		onMounted(() => {
+			NextLoading.done();
+			loginBg();
+			loginApp()
+		});
+		return {
+			logoMini,
+			loginIconTwo,
+			getThemeConfig,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped lang="scss">
+.login-container {
+	width: 100%;
+	height: 100%;
+	position: relative;
+	z-index: 999;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	background-image: radial-gradient(at center, #0075c3, #000b61);
+
+	canvas {
+		display: block;
+		vertical-align: bottom;
+	}
+
+	#particles-js {
+		width: 100%;
+		height: 100%;
+
+		background-size: cover;
+		background-position: 50% 50%;
+		background-repeat: no-repeat;
+		width: 100%;
+		height: 100%;
+		position: absolute;
+		top: 0;
+		left: 0;
+	}
+
+	.loginContent{
+		width: 100%;
+		padding: 0 300px;
+		display: flex;
+		align-items: flex-start;
+		justify-content: space-between;
+
+		.loginContL{
+			font-size: 48px;
+			font-weight: bold;
+			padding-top: 20px;
+			margin-right: 30px;
+
+			.apTitleT{
+				color: #fff;
+				margin-bottom: 20px;
+				letter-spacing: 4px;
+			}
+			.apTitleB{
+				color: #01d0ff;
+				margin-bottom: 40px;
+				letter-spacing: 4px;
+			}
+			&>span{
+				display: block;
+				width: 120px;
+				height: 8px;
+				background: #01d0ff;
+			}
+		}
+		.loginPanel{
+			padding: 85px 70px;
+			background: #fff;
+			border-radius: 15px;
+			box-shadow: 0 8px 40px rgba(0,0,0,.15);
+
+			.welc{
+				font-size: 36px;
+				font-family: "PingFang SC";
+				font-weight: normal;
+				color: #999999;
+				letter-spacing: 2px;
+				margin-bottom: 15px;
+			}
+			.welcc{
+				font-size: 32px;
+				font-family: "PingFang SC";
+				font-weight: lighter;
+				color: #333;
+				letter-spacing: 2px;
+			}
+		}
+	}
+}
+</style>
diff --git a/src/views/menu/menu.vue b/src/views/menu/menu.vue
new file mode 100644
index 0000000..59702eb
--- /dev/null
+++ b/src/views/menu/menu.vue
@@ -0,0 +1,250 @@
+<template>
+	<div class="login-container">
+		<div class="topPanel">
+			<div class="topPanelCont">
+				<div class="topTit">
+					<div>新疆国泰新华安</div>
+					<span></span>
+					<div>全风险预警监测系统</div>
+				</div>
+				<div class="userInfo">
+					<div class="avator">
+						<img src="../../assets/menu/admin.png">
+						<div>admin</div>
+					</div>
+					<span></span>
+					<div class="loginOut" @click="onLoginOut">退出登录</div>
+				</div>
+			</div>
+		</div>
+
+		<div class="menuGrid">
+			<div class="gridCont">
+				<el-row :gutter="16">
+					<el-col :span="6"><div class="grid-content"><div class="itemTit">安全风险综合<br>预警预报平台</div><img class="iconImg" src="../../assets/menu/icon1.png"><img class="bgImg" src="../../assets/menu/card1.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content"><div class="itemTit">目标责任管理系统</div><img class="iconImg" src="../../assets/menu/icon2.png"><img class="bgImg" src="../../assets/menu/card2.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content"><div class="itemTit">安全知识图谱系统</div><img class="iconImg" src="../../assets/menu/icon3.png"><img class="bgImg" src="../../assets/menu/card3.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content"><div class="itemTit">双重预防系统</div><img class="iconImg" src="../../assets/menu/icon4.png"><img class="bgImg" src="../../assets/menu/card4.png"></div></el-col>
+				</el-row>
+				<el-row :gutter="16">
+					<el-col :span="6"><div class="grid-content grid-content-2"><div class="itemTit">应急管理系统</div><img class="iconImg" src="../../assets/menu/icon5.png"><img class="bgImg" src="../../assets/menu/card5.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content grid-content-2"><div class="itemTit">事故管理系统</div><img class="iconImg" src="../../assets/menu/icon6.png"><img class="bgImg" src="../../assets/menu/card6.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content grid-content-2"><div class="itemTit">特殊作业系统</div><img class="iconImg" src="../../assets/menu/icon7.png"><img class="bgImg" src="../../assets/menu/card7.png"></div></el-col>
+					<el-col :span="6"><div class="grid-content grid-content-2"><div class="itemTit">智能巡检系统</div><img class="iconImg" src="../../assets/menu/icon8.png"><img class="bgImg" src="../../assets/menu/card8.png"></div></el-col>
+				</el-row>
+				<el-row :gutter="16">
+					<el-col :span="6"><div class="grid-content grid-content-3"><div class="itemTit">设备综合管控系统</div><img class="iconImg" src="../../assets/menu/icon9.png"><img class="bgImg" src="../../assets/menu/card9.png"></div></el-col>
+					<el-col :span="9"><div class="grid-content grid-content-3"><div class="itemTit">危险化学品全生命周期安全<br>管理系统</div><img class="iconImg" src="../../assets/menu/icon10.png"><img class="bgImg" src="../../assets/menu/card10.png"></div></el-col>
+					<el-col :span="9"><div class="grid-content grid-content-3"><div class="itemTit">基础数据权限管理系统</div><img class="iconImg" src="../../assets/menu/icon11.png"><img class="bgImg" src="../../assets/menu/card11.png"></div></el-col>
+				</el-row>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive, computed, defineComponent, onMounted } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import logoMini from '/@/assets/logo-mini.svg';
+import loginIconTwo from '/@/assets/login-icon-two.svg';
+import { NextLoading } from '/@/utils/loading';
+import {Session} from "/@/utils/storage";
+
+// 定义接口来定义对象的类型
+interface LoginState {
+	tabsActiveName: string;
+	isScan: boolean;
+}
+
+export default defineComponent({
+	name: 'loginIndex',
+	components: {},
+	setup() {
+		const storesThemeConfig = useThemeConfig();
+		const { themeConfig } = storeToRefs(storesThemeConfig);
+		const state = reactive<LoginState>({
+			tabsActiveName: 'account',
+			isScan: false,
+		});
+		// 获取布局配置信息
+		const getThemeConfig = computed(() => {
+			return themeConfig.value;
+		});
+		// 下拉菜单点击时
+		const onLoginOut = () => {
+			console.log('退出登录')
+		};
+		// 页面加载时
+		onMounted(() => {
+			NextLoading.done();
+			// loginBg();
+			// loginApp()
+		});
+		return {
+			logoMini,
+			loginIconTwo,
+			getThemeConfig,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped lang="scss">
+.login-container {
+	width: 100%;
+	height: 100%;
+	position: relative;
+	background: url("../../assets/menu/bg_home.jpg") no-repeat center;
+	.topPanel{
+		position: absolute;
+		width: 100%;
+		top: -80px;
+		left: 0;
+		height:100px;
+		background: #fff;
+		display: flex;
+		justify-content: center;
+		box-shadow: 0 8px 32px rgba(0,0,0,.1);
+		animation: showDown .6s 1 ease forwards;
+
+		@keyframes showDown {
+			100%{
+				position: absolute;
+				top: 0;
+			}
+		}
+		.topPanelCont{
+			width: 1200px;
+			height: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.topTit{
+				font-size: 24px;
+				font-weight: bold;
+				display: flex;
+				align-items: center;
+				color: #333;
+				line-height: 28px;
+
+				&>div:last-of-type{
+					color: #006DF5;
+				}
+
+				span{
+					width: 1px;
+					height: 28px;
+					background: #999;
+					margin: 0 15px;
+				}
+			}
+
+			.userInfo{
+				display: flex;
+				align-items: center;
+
+				.avator{
+					display: flex;
+					justify-content: right;
+
+					img{
+						width: 20px;
+						height: 20px;
+						border-radius: 10px;
+					}
+					div{
+						font-size: 15px;
+						color: #333333;
+						line-height: 20px;
+						margin-left: 6px;
+					}
+				}
+				span{
+					width: 1px;
+					height: 20px;
+					background: #999;
+					margin: 0 15px;
+				}
+				.loginOut{
+					font-size: 15px;
+					color: #333;
+					line-height: 20px;
+					cursor: pointer;
+
+					&:hover{
+						color: #006DF5;
+					}
+				}
+			}
+		}
+	}
+
+	.menuGrid{
+		width: 100%;
+		position: absolute;
+		top: 150px;
+		display: flex;
+		justify-content: center;
+		.gridCont{
+			width: 1200px;
+			.el-row {
+				margin-bottom: 16px;
+			}
+			.el-row:last-child {
+				margin-bottom: 0;
+			}
+			.el-col {
+				border-radius: 8px;
+			}
+
+			.grid-content {
+				border-radius: 8px;
+				height: 234px;
+				padding: 32px;
+				position: relative;
+				background-image: linear-gradient(135deg,#00C0F5,#147AEA);
+				overflow: hidden;
+				cursor: pointer;
+				transition: .3s;
+				border: none;
+
+				&:hover{
+					box-shadow: 0 8px 32px rgba(20,97,234,.4);
+				}
+
+				.itemTit{
+					font-size: 24px;
+					line-height: 36px;
+					height: 40%;
+					font-family: "PingFang SC";
+					font-weight: lighter;
+					color: #fff;
+					margin-bottom: 25px;
+				}
+				.iconImg{
+					width: 80px;
+					height: 80px;
+				}
+
+				.bgImg{
+					position: absolute;
+					right: 0;
+					bottom: 0;
+				}
+			}
+
+			.grid-content-2{
+				background-image: linear-gradient(135deg,#0098F5,#1461EA);
+			}
+
+			.grid-content-3{
+				background-image: linear-gradient(135deg,#006DF5,#1450EA);
+			}
+		}
+
+	}
+}
+</style>
diff --git a/static/loginPage.js/login.js b/static/loginPage.js/login.js
new file mode 100644
index 0000000..431ef23
--- /dev/null
+++ b/static/loginPage.js/login.js
@@ -0,0 +1,1545 @@
+/* -----------------------------------------------
+/* Author : Vincent Garreau  - vincentgarreau.com
+/* MIT license: http://opensource.org/licenses/MIT
+/* Demo / Generator : vincentgarreau.com/particles.js
+/* GitHub : github.com/VincentGarreau/particles.js
+/* How to use? : Check the GitHub README
+/* v2.0.0
+/* ----------------------------------------------- */
+function loginBg() {
+var pJS = function(tag_id, params){
+
+  var canvas_el = document.querySelector('#'+tag_id+' > .particles-js-canvas-el');
+
+  /* particles.js variables with default values */
+  this.pJS = {
+    canvas: {
+      el: canvas_el,
+      w: canvas_el.offsetWidth,
+      h: canvas_el.offsetHeight
+    },
+    particles: {
+      number: {
+        value: 400,
+        density: {
+          enable: true,
+          value_area: 800
+        }
+      },
+      color: {
+        value: '#fff'
+      },
+      shape: {
+        type: 'circle',
+        stroke: {
+          width: 0,
+          color: '#ff0000'
+        },
+        polygon: {
+          nb_sides: 5
+        },
+        image: {
+          src: '',
+          width: 100,
+          height: 100
+        }
+      },
+      opacity: {
+        value: 1,
+        random: false,
+        anim: {
+          enable: false,
+          speed: 2,
+          opacity_min: 0,
+          sync: false
+        }
+      },
+      size: {
+        value: 20,
+        random: false,
+        anim: {
+          enable: false,
+          speed: 20,
+          size_min: 0,
+          sync: false
+        }
+      },
+      line_linked: {
+        enable: true,
+        distance: 100,
+        color: '#fff',
+        opacity: 1,
+        width: 1
+      },
+      move: {
+        enable: true,
+        speed: 2,
+        direction: 'none',
+        random: false,
+        straight: false,
+        out_mode: 'out',
+        bounce: false,
+        attract: {
+          enable: false,
+          rotateX: 3000,
+          rotateY: 3000
+        }
+      },
+      array: []
+    },
+    interactivity: {
+      detect_on: 'canvas',
+      events: {
+        onhover: {
+          enable: true,
+          mode: 'grab'
+        },
+        onclick: {
+          enable: true,
+          mode: 'push'
+        },
+        resize: true
+      },
+      modes: {
+        grab:{
+          distance: 100,
+          line_linked:{
+            opacity: 1
+          }
+        },
+        bubble:{
+          distance: 200,
+          size: 80,
+          duration: 0.7
+        },
+        repulse:{
+          distance: 200,
+          duration: 0.4
+        },
+        push:{
+          particles_nb: 4
+        },
+        remove:{
+          particles_nb: 2
+        }
+      },
+      mouse:{}
+    },
+    retina_detect: false,
+    fn: {
+      interact: {},
+      modes: {},
+      vendors:{}
+    },
+    tmp: {}
+  };
+
+  var pJS = this.pJS;
+
+  /* params settings */
+  if(params){
+    Object.deepExtend(pJS, params);
+  }
+
+  pJS.tmp.obj = {
+    size_value: pJS.particles.size.value,
+    size_anim_speed: pJS.particles.size.anim.speed,
+    move_speed: pJS.particles.move.speed,
+    line_linked_distance: pJS.particles.line_linked.distance,
+    line_linked_width: pJS.particles.line_linked.width,
+    mode_grab_distance: pJS.interactivity.modes.grab.distance,
+    mode_bubble_distance: pJS.interactivity.modes.bubble.distance,
+    mode_bubble_size: pJS.interactivity.modes.bubble.size,
+    mode_repulse_distance: pJS.interactivity.modes.repulse.distance
+  };
+
+
+  pJS.fn.retinaInit = function(){
+
+    if(pJS.retina_detect && window.devicePixelRatio > 1){
+      pJS.canvas.pxratio = window.devicePixelRatio; 
+      pJS.tmp.retina = true;
+    } 
+    else{
+      pJS.canvas.pxratio = 1;
+      pJS.tmp.retina = false;
+    }
+
+    pJS.canvas.w = pJS.canvas.el.offsetWidth * pJS.canvas.pxratio;
+    pJS.canvas.h = pJS.canvas.el.offsetHeight * pJS.canvas.pxratio;
+
+    pJS.particles.size.value = pJS.tmp.obj.size_value * pJS.canvas.pxratio;
+    pJS.particles.size.anim.speed = pJS.tmp.obj.size_anim_speed * pJS.canvas.pxratio;
+    pJS.particles.move.speed = pJS.tmp.obj.move_speed * pJS.canvas.pxratio;
+    pJS.particles.line_linked.distance = pJS.tmp.obj.line_linked_distance * pJS.canvas.pxratio;
+    pJS.interactivity.modes.grab.distance = pJS.tmp.obj.mode_grab_distance * pJS.canvas.pxratio;
+    pJS.interactivity.modes.bubble.distance = pJS.tmp.obj.mode_bubble_distance * pJS.canvas.pxratio;
+    pJS.particles.line_linked.width = pJS.tmp.obj.line_linked_width * pJS.canvas.pxratio;
+    pJS.interactivity.modes.bubble.size = pJS.tmp.obj.mode_bubble_size * pJS.canvas.pxratio;
+    pJS.interactivity.modes.repulse.distance = pJS.tmp.obj.mode_repulse_distance * pJS.canvas.pxratio;
+
+  };
+
+
+
+  /* ---------- pJS functions - canvas ------------ */
+
+  pJS.fn.canvasInit = function(){
+    pJS.canvas.ctx = pJS.canvas.el.getContext('2d');
+  };
+
+  pJS.fn.canvasSize = function(){
+
+    pJS.canvas.el.width = pJS.canvas.w;
+    pJS.canvas.el.height = pJS.canvas.h;
+
+    if(pJS && pJS.interactivity.events.resize){
+
+      window.addEventListener('resize', function(){
+
+          pJS.canvas.w = pJS.canvas.el.offsetWidth;
+          pJS.canvas.h = pJS.canvas.el.offsetHeight;
+
+          /* resize canvas */
+          if(pJS.tmp.retina){
+            pJS.canvas.w *= pJS.canvas.pxratio;
+            pJS.canvas.h *= pJS.canvas.pxratio;
+          }
+
+          pJS.canvas.el.width = pJS.canvas.w;
+          pJS.canvas.el.height = pJS.canvas.h;
+
+          /* repaint canvas on anim disabled */
+          if(!pJS.particles.move.enable){
+            pJS.fn.particlesEmpty();
+            pJS.fn.particlesCreate();
+            pJS.fn.particlesDraw();
+            pJS.fn.vendors.densityAutoParticles();
+          }
+
+        /* density particles enabled */
+        pJS.fn.vendors.densityAutoParticles();
+
+      });
+
+    }
+
+  };
+
+
+  pJS.fn.canvasPaint = function(){
+    pJS.canvas.ctx.fillRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+  };
+
+  pJS.fn.canvasClear = function(){
+    pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+  };
+
+
+  /* --------- pJS functions - particles ----------- */
+
+  pJS.fn.particle = function(color, opacity, position){
+
+    /* size */
+    this.radius = (pJS.particles.size.random ? Math.random() : 1) * pJS.particles.size.value;
+    if(pJS.particles.size.anim.enable){
+      this.size_status = false;
+      this.vs = pJS.particles.size.anim.speed / 100;
+      if(!pJS.particles.size.anim.sync){
+        this.vs = this.vs * Math.random();
+      }
+    }
+
+    /* position */
+    this.x = position ? position.x : Math.random() * pJS.canvas.w;
+    this.y = position ? position.y : Math.random() * pJS.canvas.h;
+
+    /* check position  - into the canvas */
+    if(this.x > pJS.canvas.w - this.radius*2) this.x = this.x - this.radius;
+    else if(this.x < this.radius*2) this.x = this.x + this.radius;
+    if(this.y > pJS.canvas.h - this.radius*2) this.y = this.y - this.radius;
+    else if(this.y < this.radius*2) this.y = this.y + this.radius;
+
+    /* check position - avoid overlap */
+    if(pJS.particles.move.bounce){
+      pJS.fn.vendors.checkOverlap(this, position);
+    }
+
+    /* color */
+    this.color = {};
+    if(typeof(color.value) == 'object'){
+
+      if(color.value instanceof Array){
+        var color_selected = color.value[Math.floor(Math.random() * pJS.particles.color.value.length)];
+        this.color.rgb = hexToRgb(color_selected);
+      }else{
+        if(color.value.r != undefined && color.value.g != undefined && color.value.b != undefined){
+          this.color.rgb = {
+            r: color.value.r,
+            g: color.value.g,
+            b: color.value.b
+          }
+        }
+        if(color.value.h != undefined && color.value.s != undefined && color.value.l != undefined){
+          this.color.hsl = {
+            h: color.value.h,
+            s: color.value.s,
+            l: color.value.l
+          }
+        }
+      }
+
+    }
+    else if(color.value == 'random'){
+      this.color.rgb = {
+        r: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
+        g: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
+        b: (Math.floor(Math.random() * (255 - 0 + 1)) + 0)
+      }
+    }
+    else if(typeof(color.value) == 'string'){
+      this.color = color;
+      this.color.rgb = hexToRgb(this.color.value);
+    }
+
+    /* opacity */
+    this.opacity = (pJS.particles.opacity.random ? Math.random() : 1) * pJS.particles.opacity.value;
+    if(pJS.particles.opacity.anim.enable){
+      this.opacity_status = false;
+      this.vo = pJS.particles.opacity.anim.speed / 100;
+      if(!pJS.particles.opacity.anim.sync){
+        this.vo = this.vo * Math.random();
+      }
+    }
+
+    /* animation - velocity for speed */
+    var velbase = {}
+    switch(pJS.particles.move.direction){
+      case 'top':
+        velbase = { x:0, y:-1 };
+      break;
+      case 'top-right':
+        velbase = { x:0.5, y:-0.5 };
+      break;
+      case 'right':
+        velbase = { x:1, y:-0 };
+      break;
+      case 'bottom-right':
+        velbase = { x:0.5, y:0.5 };
+      break;
+      case 'bottom':
+        velbase = { x:0, y:1 };
+      break;
+      case 'bottom-left':
+        velbase = { x:-0.5, y:1 };
+      break;
+      case 'left':
+        velbase = { x:-1, y:0 };
+      break;
+      case 'top-left':
+        velbase = { x:-0.5, y:-0.5 };
+      break;
+      default:
+        velbase = { x:0, y:0 };
+      break;
+    }
+
+    if(pJS.particles.move.straight){
+      this.vx = velbase.x;
+      this.vy = velbase.y;
+      if(pJS.particles.move.random){
+        this.vx = this.vx * (Math.random());
+        this.vy = this.vy * (Math.random());
+      }
+    }else{
+      this.vx = velbase.x + Math.random()-0.5;
+      this.vy = velbase.y + Math.random()-0.5;
+    }
+
+    // var theta = 2.0 * Math.PI * Math.random();
+    // this.vx = Math.cos(theta);
+    // this.vy = Math.sin(theta);
+
+    this.vx_i = this.vx;
+    this.vy_i = this.vy;
+
+    
+
+    /* if shape is image */
+
+    var shape_type = pJS.particles.shape.type;
+    if(typeof(shape_type) == 'object'){
+      if(shape_type instanceof Array){
+        var shape_selected = shape_type[Math.floor(Math.random() * shape_type.length)];
+        this.shape = shape_selected;
+      }
+    }else{
+      this.shape = shape_type;
+    }
+
+    if(this.shape == 'image'){
+      var sh = pJS.particles.shape;
+      this.img = {
+        src: sh.image.src,
+        ratio: sh.image.width / sh.image.height
+      }
+      if(!this.img.ratio) this.img.ratio = 1;
+      if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg != undefined){
+        pJS.fn.vendors.createSvgImg(this);
+        if(pJS.tmp.pushing){
+          this.img.loaded = false;
+        }
+      }
+    }
+
+    
+
+  };
+
+
+  pJS.fn.particle.prototype.draw = function() {
+
+    var p = this;
+
+    if(p.radius_bubble != undefined){
+      var radius = p.radius_bubble; 
+    }else{
+      var radius = p.radius;
+    }
+
+    if(p.opacity_bubble != undefined){
+      var opacity = p.opacity_bubble;
+    }else{
+      var opacity = p.opacity;
+    }
+
+    if(p.color.rgb){
+      var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+opacity+')';
+    }else{
+      var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+opacity+')';
+    }
+
+    pJS.canvas.ctx.fillStyle = color_value;
+    pJS.canvas.ctx.beginPath();
+
+    switch(p.shape){
+
+      case 'circle':
+        pJS.canvas.ctx.arc(p.x, p.y, radius, 0, Math.PI * 2, false);
+      break;
+
+      case 'edge':
+        pJS.canvas.ctx.rect(p.x-radius, p.y-radius, radius*2, radius*2);
+      break;
+
+      case 'triangle':
+        pJS.fn.vendors.drawShape(pJS.canvas.ctx, p.x-radius, p.y+radius / 1.66, radius*2, 3, 2);
+      break;
+
+      case 'polygon':
+        pJS.fn.vendors.drawShape(
+          pJS.canvas.ctx,
+          p.x - radius / (pJS.particles.shape.polygon.nb_sides/3.5), // startX
+          p.y - radius / (2.66/3.5), // startY
+          radius*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
+          pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
+          1 // sideCountDenominator
+        );
+      break;
+
+      case 'star':
+        pJS.fn.vendors.drawShape(
+          pJS.canvas.ctx,
+          p.x - radius*2 / (pJS.particles.shape.polygon.nb_sides/4), // startX
+          p.y - radius / (2*2.66/3.5), // startY
+          radius*2*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
+          pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
+          2 // sideCountDenominator
+        );
+      break;
+
+      case 'image':
+
+        function draw(){
+          pJS.canvas.ctx.drawImage(
+            img_obj,
+            p.x-radius,
+            p.y-radius,
+            radius*2,
+            radius*2 / p.img.ratio
+          );
+        }
+
+        if(pJS.tmp.img_type == 'svg'){
+          var img_obj = p.img.obj;
+        }else{
+          var img_obj = pJS.tmp.img_obj;
+        }
+
+        if(img_obj){
+          draw();
+        }
+
+      break;
+
+    }
+
+    pJS.canvas.ctx.closePath();
+
+    if(pJS.particles.shape.stroke.width > 0){
+      pJS.canvas.ctx.strokeStyle = pJS.particles.shape.stroke.color;
+      pJS.canvas.ctx.lineWidth = pJS.particles.shape.stroke.width;
+      pJS.canvas.ctx.stroke();
+    }
+    
+    pJS.canvas.ctx.fill();
+    
+  };
+
+
+  pJS.fn.particlesCreate = function(){
+    for(var i = 0; i < pJS.particles.number.value; i++) {
+      pJS.particles.array.push(new pJS.fn.particle(pJS.particles.color, pJS.particles.opacity.value));
+    }
+  };
+
+  pJS.fn.particlesUpdate = function(){
+
+    for(var i = 0; i < pJS.particles.array.length; i++){
+
+      /* the particle */
+      var p = pJS.particles.array[i];
+
+      // var d = ( dx = pJS.interactivity.mouse.click_pos_x - p.x ) * dx + ( dy = pJS.interactivity.mouse.click_pos_y - p.y ) * dy;
+      // var f = -BANG_SIZE / d;
+      // if ( d < BANG_SIZE ) {
+      //     var t = Math.atan2( dy, dx );
+      //     p.vx = f * Math.cos(t);
+      //     p.vy = f * Math.sin(t);
+      // }
+
+      /* move the particle */
+      if(pJS.particles.move.enable){
+        var ms = pJS.particles.move.speed/2;
+        p.x += p.vx * ms;
+        p.y += p.vy * ms;
+      }
+
+      /* change opacity status */
+      if(pJS.particles.opacity.anim.enable) {
+        if(p.opacity_status == true) {
+          if(p.opacity >= pJS.particles.opacity.value) p.opacity_status = false;
+          p.opacity += p.vo;
+        }else {
+          if(p.opacity <= pJS.particles.opacity.anim.opacity_min) p.opacity_status = true;
+          p.opacity -= p.vo;
+        }
+        if(p.opacity < 0) p.opacity = 0;
+      }
+
+      /* change size */
+      if(pJS.particles.size.anim.enable){
+        if(p.size_status == true){
+          if(p.radius >= pJS.particles.size.value) p.size_status = false;
+          p.radius += p.vs;
+        }else{
+          if(p.radius <= pJS.particles.size.anim.size_min) p.size_status = true;
+          p.radius -= p.vs;
+        }
+        if(p.radius < 0) p.radius = 0;
+      }
+
+      /* change particle position if it is out of canvas */
+      if(pJS.particles.move.out_mode == 'bounce'){
+        var new_pos = {
+          x_left: p.radius,
+          x_right:  pJS.canvas.w,
+          y_top: p.radius,
+          y_bottom: pJS.canvas.h
+        }
+      }else{
+        var new_pos = {
+          x_left: -p.radius,
+          x_right: pJS.canvas.w + p.radius,
+          y_top: -p.radius,
+          y_bottom: pJS.canvas.h + p.radius
+        }
+      }
+
+      if(p.x - p.radius > pJS.canvas.w){
+        p.x = new_pos.x_left;
+        p.y = Math.random() * pJS.canvas.h;
+      }
+      else if(p.x + p.radius < 0){
+        p.x = new_pos.x_right;
+        p.y = Math.random() * pJS.canvas.h;
+      }
+      if(p.y - p.radius > pJS.canvas.h){
+        p.y = new_pos.y_top;
+        p.x = Math.random() * pJS.canvas.w;
+      }
+      else if(p.y + p.radius < 0){
+        p.y = new_pos.y_bottom;
+        p.x = Math.random() * pJS.canvas.w;
+      }
+
+      /* out of canvas modes */
+      switch(pJS.particles.move.out_mode){
+        case 'bounce':
+          if (p.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
+          else if (p.x - p.radius < 0) p.vx = -p.vx;
+          if (p.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
+          else if (p.y - p.radius < 0) p.vy = -p.vy;
+        break;
+      }
+
+      /* events */
+      if(isInArray('grab', pJS.interactivity.events.onhover.mode)){
+        pJS.fn.modes.grabParticle(p);
+      }
+
+      if(isInArray('bubble', pJS.interactivity.events.onhover.mode) || isInArray('bubble', pJS.interactivity.events.onclick.mode)){
+        pJS.fn.modes.bubbleParticle(p);
+      }
+
+      if(isInArray('repulse', pJS.interactivity.events.onhover.mode) || isInArray('repulse', pJS.interactivity.events.onclick.mode)){
+        pJS.fn.modes.repulseParticle(p);
+      }
+
+      /* interaction auto between particles */
+      if(pJS.particles.line_linked.enable || pJS.particles.move.attract.enable){
+        for(var j = i + 1; j < pJS.particles.array.length; j++){
+          var p2 = pJS.particles.array[j];
+
+          /* link particles */
+          if(pJS.particles.line_linked.enable){
+            pJS.fn.interact.linkParticles(p,p2);
+          }
+
+          /* attract particles */
+          if(pJS.particles.move.attract.enable){
+            pJS.fn.interact.attractParticles(p,p2);
+          }
+
+          /* bounce particles */
+          if(pJS.particles.move.bounce){
+            pJS.fn.interact.bounceParticles(p,p2);
+          }
+
+        }
+      }
+
+
+    }
+
+  };
+
+  pJS.fn.particlesDraw = function(){
+
+    /* clear canvas */
+    pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+
+    /* update each particles param */
+    pJS.fn.particlesUpdate();
+
+    /* draw each particle */
+    for(var i = 0; i < pJS.particles.array.length; i++){
+      var p = pJS.particles.array[i];
+      p.draw();
+    }
+
+  };
+
+  pJS.fn.particlesEmpty = function(){
+    pJS.particles.array = [];
+  };
+
+  pJS.fn.particlesRefresh = function(){
+
+    /* init all */
+    cancelRequestAnimFrame(pJS.fn.checkAnimFrame);
+    cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+    pJS.tmp.source_svg = undefined;
+    pJS.tmp.img_obj = undefined;
+    pJS.tmp.count_svg = 0;
+    pJS.fn.particlesEmpty();
+    pJS.fn.canvasClear();
+    
+    /* restart */
+    pJS.fn.vendors.start();
+
+  };
+
+
+  /* ---------- pJS functions - particles interaction ------------ */
+
+  pJS.fn.interact.linkParticles = function(p1, p2){
+
+    var dx = p1.x - p2.x,
+        dy = p1.y - p2.y,
+        dist = Math.sqrt(dx*dx + dy*dy);
+
+    /* draw a line between p1 and p2 if the distance between them is under the config distance */
+    if(dist <= pJS.particles.line_linked.distance){
+
+      var opacity_line = pJS.particles.line_linked.opacity - (dist / (1/pJS.particles.line_linked.opacity)) / pJS.particles.line_linked.distance;
+
+      if(opacity_line > 0){        
+        
+        /* style */
+        var color_line = pJS.particles.line_linked.color_rgb_line;
+        pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
+        pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
+        //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
+        
+        /* path */
+        pJS.canvas.ctx.beginPath();
+        pJS.canvas.ctx.moveTo(p1.x, p1.y);
+        pJS.canvas.ctx.lineTo(p2.x, p2.y);
+        pJS.canvas.ctx.stroke();
+        pJS.canvas.ctx.closePath();
+
+      }
+
+    }
+
+  };
+
+
+  pJS.fn.interact.attractParticles  = function(p1, p2){
+
+    /* condensed particles */
+    var dx = p1.x - p2.x,
+        dy = p1.y - p2.y,
+        dist = Math.sqrt(dx*dx + dy*dy);
+
+    if(dist <= pJS.particles.line_linked.distance){
+
+      var ax = dx/(pJS.particles.move.attract.rotateX*1000),
+          ay = dy/(pJS.particles.move.attract.rotateY*1000);
+
+      p1.vx -= ax;
+      p1.vy -= ay;
+
+      p2.vx += ax;
+      p2.vy += ay;
+
+    }
+    
+
+  }
+
+
+  pJS.fn.interact.bounceParticles = function(p1, p2){
+
+    var dx = p1.x - p2.x,
+        dy = p1.y - p2.y,
+        dist = Math.sqrt(dx*dx + dy*dy),
+        dist_p = p1.radius+p2.radius;
+
+    if(dist <= dist_p){
+      p1.vx = -p1.vx;
+      p1.vy = -p1.vy;
+
+      p2.vx = -p2.vx;
+      p2.vy = -p2.vy;
+    }
+
+  }
+
+
+  /* ---------- pJS functions - modes events ------------ */
+
+  pJS.fn.modes.pushParticles = function(nb, pos){
+
+    pJS.tmp.pushing = true;
+
+    for(var i = 0; i < nb; i++){
+      pJS.particles.array.push(
+        new pJS.fn.particle(
+          pJS.particles.color,
+          pJS.particles.opacity.value,
+          {
+            'x': pos ? pos.pos_x : Math.random() * pJS.canvas.w,
+            'y': pos ? pos.pos_y : Math.random() * pJS.canvas.h
+          }
+        )
+      )
+      if(i == nb-1){
+        if(!pJS.particles.move.enable){
+          pJS.fn.particlesDraw();
+        }
+        pJS.tmp.pushing = false;
+      }
+    }
+
+  };
+
+
+  pJS.fn.modes.removeParticles = function(nb){
+
+    pJS.particles.array.splice(0, nb);
+    if(!pJS.particles.move.enable){
+      pJS.fn.particlesDraw();
+    }
+
+  };
+
+
+  pJS.fn.modes.bubbleParticle = function(p){
+
+    /* on hover event */
+    if(pJS.interactivity.events.onhover.enable && isInArray('bubble', pJS.interactivity.events.onhover.mode)){
+
+      var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+          dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+          dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
+          ratio = 1 - dist_mouse / pJS.interactivity.modes.bubble.distance;
+
+      function init(){
+        p.opacity_bubble = p.opacity;
+        p.radius_bubble = p.radius;
+      }
+
+      /* mousemove - check ratio */
+      if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
+
+        if(ratio >= 0 && pJS.interactivity.status == 'mousemove'){
+          
+          /* size */
+          if(pJS.interactivity.modes.bubble.size != pJS.particles.size.value){
+
+            if(pJS.interactivity.modes.bubble.size > pJS.particles.size.value){
+              var size = p.radius + (pJS.interactivity.modes.bubble.size*ratio);
+              if(size >= 0){
+                p.radius_bubble = size;
+              }
+            }else{
+              var dif = p.radius - pJS.interactivity.modes.bubble.size,
+                  size = p.radius - (dif*ratio);
+              if(size > 0){
+                p.radius_bubble = size;
+              }else{
+                p.radius_bubble = 0;
+              }
+            }
+
+          }
+
+          /* opacity */
+          if(pJS.interactivity.modes.bubble.opacity != pJS.particles.opacity.value){
+
+            if(pJS.interactivity.modes.bubble.opacity > pJS.particles.opacity.value){
+              var opacity = pJS.interactivity.modes.bubble.opacity*ratio;
+              if(opacity > p.opacity && opacity <= pJS.interactivity.modes.bubble.opacity){
+                p.opacity_bubble = opacity;
+              }
+            }else{
+              var opacity = p.opacity - (pJS.particles.opacity.value-pJS.interactivity.modes.bubble.opacity)*ratio;
+              if(opacity < p.opacity && opacity >= pJS.interactivity.modes.bubble.opacity){
+                p.opacity_bubble = opacity;
+              }
+            }
+
+          }
+
+        }
+
+      }else{
+        init();
+      }
+
+
+      /* mouseleave */
+      if(pJS.interactivity.status == 'mouseleave'){
+        init();
+      }
+    
+    }
+
+    /* on click event */
+    else if(pJS.interactivity.events.onclick.enable && isInArray('bubble', pJS.interactivity.events.onclick.mode)){
+
+
+      if(pJS.tmp.bubble_clicking){
+        var dx_mouse = p.x - pJS.interactivity.mouse.click_pos_x,
+            dy_mouse = p.y - pJS.interactivity.mouse.click_pos_y,
+            dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
+            time_spent = (new Date().getTime() - pJS.interactivity.mouse.click_time)/1000;
+
+        if(time_spent > pJS.interactivity.modes.bubble.duration){
+          pJS.tmp.bubble_duration_end = true;
+        }
+
+        if(time_spent > pJS.interactivity.modes.bubble.duration*2){
+          pJS.tmp.bubble_clicking = false;
+          pJS.tmp.bubble_duration_end = false;
+        }
+      }
+
+
+      function process(bubble_param, particles_param, p_obj_bubble, p_obj, id){
+
+        if(bubble_param != particles_param){
+
+          if(!pJS.tmp.bubble_duration_end){
+            if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
+              if(p_obj_bubble != undefined) var obj = p_obj_bubble;
+              else var obj = p_obj;
+              if(obj != bubble_param){
+                var value = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration);
+                if(id == 'size') p.radius_bubble = value;
+                if(id == 'opacity') p.opacity_bubble = value;
+              }
+            }else{
+              if(id == 'size') p.radius_bubble = undefined;
+              if(id == 'opacity') p.opacity_bubble = undefined;
+            }
+          }else{
+            if(p_obj_bubble != undefined){
+              var value_tmp = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration),
+                  dif = bubble_param - value_tmp;
+                  value = bubble_param + dif;
+              if(id == 'size') p.radius_bubble = value;
+              if(id == 'opacity') p.opacity_bubble = value;
+            }
+          }
+
+        }
+
+      }
+
+      if(pJS.tmp.bubble_clicking){
+        /* size */
+        process(pJS.interactivity.modes.bubble.size, pJS.particles.size.value, p.radius_bubble, p.radius, 'size');
+        /* opacity */
+        process(pJS.interactivity.modes.bubble.opacity, pJS.particles.opacity.value, p.opacity_bubble, p.opacity, 'opacity');
+      }
+
+    }
+
+  };
+
+
+  pJS.fn.modes.repulseParticle = function(p){
+
+    if(pJS.interactivity.events.onhover.enable && isInArray('repulse', pJS.interactivity.events.onhover.mode) && pJS.interactivity.status == 'mousemove') {
+
+      var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+          dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+          dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
+
+      var normVec = {x: dx_mouse/dist_mouse, y: dy_mouse/dist_mouse},
+          repulseRadius = pJS.interactivity.modes.repulse.distance,
+          velocity = 100,
+          repulseFactor = clamp((1/repulseRadius)*(-1*Math.pow(dist_mouse/repulseRadius,2)+1)*repulseRadius*velocity, 0, 50);
+      
+      var pos = {
+        x: p.x + normVec.x * repulseFactor,
+        y: p.y + normVec.y * repulseFactor
+      }
+
+      if(pJS.particles.move.out_mode == 'bounce'){
+        if(pos.x - p.radius > 0 && pos.x + p.radius < pJS.canvas.w) p.x = pos.x;
+        if(pos.y - p.radius > 0 && pos.y + p.radius < pJS.canvas.h) p.y = pos.y;
+      }else{
+        p.x = pos.x;
+        p.y = pos.y;
+      }
+    
+    }
+
+
+    else if(pJS.interactivity.events.onclick.enable && isInArray('repulse', pJS.interactivity.events.onclick.mode)) {
+
+      if(!pJS.tmp.repulse_finish){
+        pJS.tmp.repulse_count++;
+        if(pJS.tmp.repulse_count == pJS.particles.array.length){
+          pJS.tmp.repulse_finish = true;
+        }
+      }
+
+      if(pJS.tmp.repulse_clicking){
+
+        var repulseRadius = Math.pow(pJS.interactivity.modes.repulse.distance/6, 3);
+
+        var dx = pJS.interactivity.mouse.click_pos_x - p.x,
+            dy = pJS.interactivity.mouse.click_pos_y - p.y,
+            d = dx*dx + dy*dy;
+
+        var force = -repulseRadius / d * 1;
+
+        function process(){
+
+          var f = Math.atan2(dy,dx);
+          p.vx = force * Math.cos(f);
+          p.vy = force * Math.sin(f);
+
+          if(pJS.particles.move.out_mode == 'bounce'){
+            var pos = {
+              x: p.x + p.vx,
+              y: p.y + p.vy
+            }
+            if (pos.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
+            else if (pos.x - p.radius < 0) p.vx = -p.vx;
+            if (pos.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
+            else if (pos.y - p.radius < 0) p.vy = -p.vy;
+          }
+
+        }
+
+        // default
+        if(d <= repulseRadius){
+          process();
+        }
+
+        // bang - slow motion mode
+        // if(!pJS.tmp.repulse_finish){
+        //   if(d <= repulseRadius){
+        //     process();
+        //   }
+        // }else{
+        //   process();
+        // }
+        
+
+      }else{
+
+        if(pJS.tmp.repulse_clicking == false){
+
+          p.vx = p.vx_i;
+          p.vy = p.vy_i;
+        
+        }
+
+      }
+
+    }
+
+  }
+
+
+  pJS.fn.modes.grabParticle = function(p){
+
+    if(pJS.interactivity.events.onhover.enable && pJS.interactivity.status == 'mousemove'){
+
+      var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+          dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+          dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
+
+      /* draw a line between the cursor and the particle if the distance between them is under the config distance */
+      if(dist_mouse <= pJS.interactivity.modes.grab.distance){
+
+        var opacity_line = pJS.interactivity.modes.grab.line_linked.opacity - (dist_mouse / (1/pJS.interactivity.modes.grab.line_linked.opacity)) / pJS.interactivity.modes.grab.distance;
+
+        if(opacity_line > 0){
+
+          /* style */
+          var color_line = pJS.particles.line_linked.color_rgb_line;
+          pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
+          pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
+          //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
+          
+          /* path */
+          pJS.canvas.ctx.beginPath();
+          pJS.canvas.ctx.moveTo(p.x, p.y);
+          pJS.canvas.ctx.lineTo(pJS.interactivity.mouse.pos_x, pJS.interactivity.mouse.pos_y);
+          pJS.canvas.ctx.stroke();
+          pJS.canvas.ctx.closePath();
+
+        }
+
+      }
+
+    }
+
+  };
+
+
+
+  /* ---------- pJS functions - vendors ------------ */
+
+  pJS.fn.vendors.eventsListeners = function(){
+
+    /* events target element */
+    if(pJS.interactivity.detect_on == 'window'){
+      pJS.interactivity.el = window;
+    }else{
+      pJS.interactivity.el = pJS.canvas.el;
+    }
+
+
+    /* detect mouse pos - on hover / click event */
+    if(pJS.interactivity.events.onhover.enable || pJS.interactivity.events.onclick.enable){
+
+      /* el on mousemove */
+      pJS.interactivity.el.addEventListener('mousemove', function(e){
+
+        if(pJS.interactivity.el == window){
+          var pos_x = e.clientX,
+              pos_y = e.clientY;
+        }
+        else{
+          var pos_x = e.offsetX || e.clientX,
+              pos_y = e.offsetY || e.clientY;
+        }
+
+        pJS.interactivity.mouse.pos_x = pos_x;
+        pJS.interactivity.mouse.pos_y = pos_y;
+
+        if(pJS.tmp.retina){
+          pJS.interactivity.mouse.pos_x *= pJS.canvas.pxratio;
+          pJS.interactivity.mouse.pos_y *= pJS.canvas.pxratio;
+        }
+
+        pJS.interactivity.status = 'mousemove';
+
+      });
+
+      /* el on onmouseleave */
+      pJS.interactivity.el.addEventListener('mouseleave', function(e){
+
+        pJS.interactivity.mouse.pos_x = null;
+        pJS.interactivity.mouse.pos_y = null;
+        pJS.interactivity.status = 'mouseleave';
+
+      });
+
+    }
+
+    /* on click event */
+    if(pJS.interactivity.events.onclick.enable){
+
+      pJS.interactivity.el.addEventListener('click', function(){
+
+        pJS.interactivity.mouse.click_pos_x = pJS.interactivity.mouse.pos_x;
+        pJS.interactivity.mouse.click_pos_y = pJS.interactivity.mouse.pos_y;
+        pJS.interactivity.mouse.click_time = new Date().getTime();
+
+        if(pJS.interactivity.events.onclick.enable){
+
+          switch(pJS.interactivity.events.onclick.mode){
+
+            case 'push':
+              if(pJS.particles.move.enable){
+                pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
+              }else{
+                if(pJS.interactivity.modes.push.particles_nb == 1){
+                  pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
+                }
+                else if(pJS.interactivity.modes.push.particles_nb > 1){
+                  pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb);
+                }
+              }
+            break;
+
+            case 'remove':
+              pJS.fn.modes.removeParticles(pJS.interactivity.modes.remove.particles_nb);
+            break;
+
+            case 'bubble':
+              pJS.tmp.bubble_clicking = true;
+            break;
+
+            case 'repulse':
+              pJS.tmp.repulse_clicking = true;
+              pJS.tmp.repulse_count = 0;
+              pJS.tmp.repulse_finish = false;
+              setTimeout(function(){
+                pJS.tmp.repulse_clicking = false;
+              }, pJS.interactivity.modes.repulse.duration*1000)
+            break;
+
+          }
+
+        }
+
+      });
+        
+    }
+
+
+  };
+
+  pJS.fn.vendors.densityAutoParticles = function(){
+
+    if(pJS.particles.number.density.enable){
+
+      /* calc area */
+      var area = pJS.canvas.el.width * pJS.canvas.el.height / 1000;
+      if(pJS.tmp.retina){
+        area = area/(pJS.canvas.pxratio*2);
+      }
+
+      /* calc number of particles based on density area */
+      var nb_particles = area * pJS.particles.number.value / pJS.particles.number.density.value_area;
+
+      /* add or remove X particles */
+      var missing_particles = pJS.particles.array.length - nb_particles;
+      if(missing_particles < 0) pJS.fn.modes.pushParticles(Math.abs(missing_particles));
+      else pJS.fn.modes.removeParticles(missing_particles);
+
+    }
+
+  };
+
+
+  pJS.fn.vendors.checkOverlap = function(p1, position){
+    for(var i = 0; i < pJS.particles.array.length; i++){
+      var p2 = pJS.particles.array[i];
+
+      var dx = p1.x - p2.x,
+          dy = p1.y - p2.y,
+          dist = Math.sqrt(dx*dx + dy*dy);
+
+      if(dist <= p1.radius + p2.radius){
+        p1.x = position ? position.x : Math.random() * pJS.canvas.w;
+        p1.y = position ? position.y : Math.random() * pJS.canvas.h;
+        pJS.fn.vendors.checkOverlap(p1);
+      }
+    }
+  };
+
+
+  pJS.fn.vendors.createSvgImg = function(p){
+
+    /* set color to svg element */
+    var svgXml = pJS.tmp.source_svg,
+        rgbHex = /#([0-9A-F]{3,6})/gi,
+        coloredSvgXml = svgXml.replace(rgbHex, function (m, r, g, b) {
+          if(p.color.rgb){
+            var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+p.opacity+')';
+          }else{
+            var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+p.opacity+')';
+          }
+          return color_value;
+        });
+
+    /* prepare to create img with colored svg */
+    var svg = new Blob([coloredSvgXml], {type: 'image/svg+xml;charset=utf-8'}),
+        DOMURL = window.URL || window.webkitURL || window,
+        url = DOMURL.createObjectURL(svg);
+
+    /* create particle img obj */
+    var img = new Image();
+    img.addEventListener('load', function(){
+      p.img.obj = img;
+      p.img.loaded = true;
+      DOMURL.revokeObjectURL(url);
+      pJS.tmp.count_svg++;
+    });
+    img.src = url;
+
+  };
+
+
+  pJS.fn.vendors.destroypJS = function(){
+    cancelAnimationFrame(pJS.fn.drawAnimFrame);
+    canvas_el.remove();
+    pJSDom = null;
+  };
+
+
+  pJS.fn.vendors.drawShape = function(c, startX, startY, sideLength, sideCountNumerator, sideCountDenominator){
+
+    // By Programming Thomas - https://programmingthomas.wordpress.com/2013/04/03/n-sided-shapes/
+    var sideCount = sideCountNumerator * sideCountDenominator;
+    var decimalSides = sideCountNumerator / sideCountDenominator;
+    var interiorAngleDegrees = (180 * (decimalSides - 2)) / decimalSides;
+    var interiorAngle = Math.PI - Math.PI * interiorAngleDegrees / 180; // convert to radians
+    c.save();
+    c.beginPath();
+    c.translate(startX, startY);
+    c.moveTo(0,0);
+    for (var i = 0; i < sideCount; i++) {
+      c.lineTo(sideLength,0);
+      c.translate(sideLength,0);
+      c.rotate(interiorAngle);
+    }
+    //c.stroke();
+    c.fill();
+    c.restore();
+
+  };
+
+  pJS.fn.vendors.exportImg = function(){
+    window.open(pJS.canvas.el.toDataURL('image/png'), '_blank');
+  };
+
+
+  pJS.fn.vendors.loadImg = function(type){
+
+    pJS.tmp.img_error = undefined;
+
+    if(pJS.particles.shape.image.src != ''){
+
+      if(type == 'svg'){
+
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', pJS.particles.shape.image.src);
+        xhr.onreadystatechange = function (data) {
+          if(xhr.readyState == 4){
+            if(xhr.status == 200){
+              pJS.tmp.source_svg = data.currentTarget.response;
+              pJS.fn.vendors.checkBeforeDraw();
+            }else{
+              console.log('Error pJS - Image not found');
+              pJS.tmp.img_error = true;
+            }
+          }
+        }
+        xhr.send();
+
+      }else{
+
+        var img = new Image();
+        img.addEventListener('load', function(){
+          pJS.tmp.img_obj = img;
+          pJS.fn.vendors.checkBeforeDraw();
+        });
+        img.src = pJS.particles.shape.image.src;
+
+      }
+
+    }else{
+      console.log('Error pJS - No image.src');
+      pJS.tmp.img_error = true;
+    }
+
+  };
+
+
+  pJS.fn.vendors.draw = function(){
+
+    if(pJS.particles.shape.type == 'image'){
+
+      if(pJS.tmp.img_type == 'svg'){
+
+        if(pJS.tmp.count_svg >= pJS.particles.number.value){
+          pJS.fn.particlesDraw();
+          if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+          else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+        }else{
+          //console.log('still loading...');
+          if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+        }
+
+      }else{
+
+        if(pJS.tmp.img_obj != undefined){
+          pJS.fn.particlesDraw();
+          if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+          else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+        }else{
+          if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+        }
+
+      }
+
+    }else{
+      pJS.fn.particlesDraw();
+      if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+      else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+    }
+
+  };
+
+
+  pJS.fn.vendors.checkBeforeDraw = function(){
+
+    // if shape is image
+    if(pJS.particles.shape.type == 'image'){
+
+      if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg == undefined){
+        pJS.tmp.checkAnimFrame = requestAnimFrame(check);
+      }else{
+        //console.log('images loaded! cancel check');
+        cancelRequestAnimFrame(pJS.tmp.checkAnimFrame);
+        if(!pJS.tmp.img_error){
+          pJS.fn.vendors.init();
+          pJS.fn.vendors.draw();
+        }
+        
+      }
+
+    }else{
+      pJS.fn.vendors.init();
+      pJS.fn.vendors.draw();
+    }
+
+  };
+
+
+  pJS.fn.vendors.init = function(){
+
+    /* init canvas + particles */
+    pJS.fn.retinaInit();
+    pJS.fn.canvasInit();
+    pJS.fn.canvasSize();
+    pJS.fn.canvasPaint();
+    pJS.fn.particlesCreate();
+    pJS.fn.vendors.densityAutoParticles();
+
+    /* particles.line_linked - convert hex colors to rgb */
+    pJS.particles.line_linked.color_rgb_line = hexToRgb(pJS.particles.line_linked.color);
+
+  };
+
+
+  pJS.fn.vendors.start = function(){
+
+    if(isInArray('image', pJS.particles.shape.type)){
+      pJS.tmp.img_type = pJS.particles.shape.image.src.substr(pJS.particles.shape.image.src.length - 3);
+      pJS.fn.vendors.loadImg(pJS.tmp.img_type);
+    }else{
+      pJS.fn.vendors.checkBeforeDraw();
+    }
+
+  };
+
+
+
+
+  /* ---------- pJS - start ------------ */
+
+
+  pJS.fn.vendors.eventsListeners();
+
+  pJS.fn.vendors.start();
+  
+
+
+};
+
+/* ---------- global functions - vendors ------------ */
+
+Object.deepExtend = function ED(destination, source) {
+  for (var property in source) {
+    if (source[property] && source[property].constructor &&
+     source[property].constructor === Object) {
+      destination[property] = destination[property] || {};
+      ED(destination[property], source[property]);
+    } else {
+      destination[property] = source[property];
+    }
+  }
+  return destination;
+};
+
+window.requestAnimFrame = (function(){
+  return  window.requestAnimationFrame ||
+    window.webkitRequestAnimationFrame ||
+    window.mozRequestAnimationFrame    ||
+    window.oRequestAnimationFrame      ||
+    window.msRequestAnimationFrame     ||
+    function(callback){
+      window.setTimeout(callback, 1000 / 60);
+    };
+})();
+
+window.cancelRequestAnimFrame = ( function() {
+  return window.cancelAnimationFrame         ||
+    window.webkitCancelRequestAnimationFrame ||
+    window.mozCancelRequestAnimationFrame    ||
+    window.oCancelRequestAnimationFrame      ||
+    window.msCancelRequestAnimationFrame     ||
+    clearTimeout
+} )();
+
+function hexToRgb(hex){
+  // By Tim Down - http://stackoverflow.com/a/5624139/3493650
+  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
+  var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+  hex = hex.replace(shorthandRegex, function(m, r, g, b) {
+     return r + r + g + g + b + b;
+  });
+  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+  return result ? {
+      r: parseInt(result[1], 16),
+      g: parseInt(result[2], 16),
+      b: parseInt(result[3], 16)
+  } : null;
+};
+
+function clamp(number, min, max) {
+  return Math.min(Math.max(number, min), max);
+};
+
+function isInArray(value, array) {
+  return array.indexOf(value) > -1;
+}
+
+
+/* ---------- particles.js functions - start ------------ */
+
+window.pJSDom = [];
+
+window.particlesJS = function(tag_id, params){
+
+  //console.log(params);
+
+  /* no string id? so it's object params, and set the id with default id */
+  if(typeof(tag_id) != 'string'){
+    params = tag_id;
+    tag_id = 'particles-js';
+  }
+
+  /* no id? set the id to default id */
+  if(!tag_id){
+    tag_id = 'particles-js';
+  }
+
+  /* pJS elements */
+  var pJS_tag = document.getElementById(tag_id),
+      pJS_canvas_class = 'particles-js-canvas-el',
+      exist_canvas = pJS_tag.getElementsByClassName(pJS_canvas_class);
+
+  /* remove canvas if exists into the pJS target tag */
+  if(exist_canvas.length){
+    while(exist_canvas.length > 0){
+      pJS_tag.removeChild(exist_canvas[0]);
+    }
+  }
+
+  /* create canvas element */
+  var canvas_el = document.createElement('canvas');
+  canvas_el.className = pJS_canvas_class;
+
+  /* set size canvas */
+  canvas_el.style.width = "100%";
+  canvas_el.style.height = "100%";
+
+  /* append canvas */
+  var canvas = document.getElementById(tag_id).appendChild(canvas_el);
+
+  /* launch particle.js */
+  if(canvas != null){
+    pJSDom.push(new pJS(tag_id, params));
+  }
+
+};
+
+window.particlesJS.load = function(tag_id, path_config_json, callback){
+
+  /* load json config */
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', path_config_json);
+  xhr.onreadystatechange = function (data) {
+    if(xhr.readyState == 4){
+      if(xhr.status == 200){
+        var params = JSON.parse(data.currentTarget.response);
+        window.particlesJS(tag_id, params);
+        if(callback) callback();
+      }else{
+        console.log('Error pJS - XMLHttpRequest status: '+xhr.status);
+        console.log('Error pJS - File config not found');
+      }
+    }
+  };
+  xhr.send();
+
+};
+}
+export {
+  loginBg
+}
\ No newline at end of file
diff --git a/static/loginPage.js/loginApp.js b/static/loginPage.js/loginApp.js
new file mode 100644
index 0000000..c5dd94b
--- /dev/null
+++ b/static/loginPage.js/loginApp.js
@@ -0,0 +1,137 @@
+/* -----------------------------------------------
+/* How to use? : Check the GitHub README
+/* ----------------------------------------------- */
+
+/* To load a config file (particles.json) you need to host this demo (MAMP/WAMP/local)... */
+/*
+particlesJS.load('particles-js', 'particles.json', function() {
+  console.log('particles.js loaded - callback');
+});
+*/
+
+/* Otherwise just put the config content (json): */
+function loginApp(){
+particlesJS('particles-js',
+  
+  {
+    "particles": {
+      "number": {
+        "value": 80,
+        "density": {
+          "enable": true,
+          "value_area": 800
+        }
+      },
+      "color": {
+        "value": "#ffffff"
+      },
+      "shape": {
+        "type": "circle",
+        "stroke": {
+          "width": 0,
+          "color": "#000000"
+        },
+        "polygon": {
+          "nb_sides": 5
+        },
+        "image": {
+          "src": "img/github.svg",
+          "width": 100,
+          "height": 100
+        }
+      },
+      "opacity": {
+        "value": 0.5,
+        "random": false,
+        "anim": {
+          "enable": false,
+          "speed": 1,
+          "opacity_min": 0.1,
+          "sync": false
+        }
+      },
+      "size": {
+        "value": 5,
+        "random": true,
+        "anim": {
+          "enable": false,
+          "speed": 40,
+          "size_min": 0.1,
+          "sync": false
+        }
+      },
+      "line_linked": {
+        "enable": true,
+        "distance": 150,
+        "color": "#ffffff",
+        "opacity": 0.4,
+        "width": 1
+      },
+      "move": {
+        "enable": true,
+        "speed": 6,
+        "direction": "none",
+        "random": false,
+        "straight": false,
+        "out_mode": "out",
+        "attract": {
+          "enable": false,
+          "rotateX": 600,
+          "rotateY": 1200
+        }
+      }
+    },
+    "interactivity": {
+      "detect_on": "canvas",
+      "events": {
+        "onhover": {
+          "enable": true,
+          "mode": "repulse"
+        },
+        "onclick": {
+          "enable": true,
+          "mode": "push"
+        },
+        "resize": true
+      },
+      "modes": {
+        "grab": {
+          "distance": 400,
+          "line_linked": {
+            "opacity": 1
+          }
+        },
+        "bubble": {
+          "distance": 400,
+          "size": 40,
+          "duration": 2,
+          "opacity": 8,
+          "speed": 3
+        },
+        "repulse": {
+          "distance": 200
+        },
+        "push": {
+          "particles_nb": 4
+        },
+        "remove": {
+          "particles_nb": 2
+        }
+      }
+    },
+    "retina_detect": true,
+    "config_demo": {
+      "hide_card": false,
+      "background_color": "#b61924",
+      "background_image": "",
+      "background_position": "50% 50%",
+      "background_repeat": "no-repeat",
+      "background_size": "cover"
+    }
+  }
+
+);
+}
+export {
+  loginApp
+}
\ No newline at end of file

--
Gitblit v1.9.2