+
+
+
+
+
diff --git a/resources/assets/js/routes.js b/resources/assets/js/routes.js
new file mode 100644
index 0000000..3c301d7
--- /dev/null
+++ b/resources/assets/js/routes.js
@@ -0,0 +1,15 @@
+import { authGuard, guestGuard } from './utils/router'
+
+export default [
+ { path: '/', name: 'welcome', component: require('pages/welcome.vue') },
+
+ ...authGuard([
+ { path: '/home', name: 'home', component: require('pages/home.vue') }
+ ]),
+
+ ...guestGuard([
+ { path: '/auth/login', name: 'auth.login', component: require('pages/auth/login.vue') },
+ { path: '/auth/register', name: 'auth.register', component: require('pages/auth/register.vue') },
+ { path: '/password/reset', name: 'password.reset', component: require('pages/password/reset.vue') }
+ ])
+]
diff --git a/resources/assets/js/store/index.js b/resources/assets/js/store/index.js
new file mode 100644
index 0000000..55aa18d
--- /dev/null
+++ b/resources/assets/js/store/index.js
@@ -0,0 +1,10 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ modules: {
+ ...require('./modules/auth')
+ }
+})
diff --git a/resources/assets/js/store/modules/auth.js b/resources/assets/js/store/modules/auth.js
new file mode 100644
index 0000000..8829273
--- /dev/null
+++ b/resources/assets/js/store/modules/auth.js
@@ -0,0 +1,62 @@
+import Vue from 'vue'
+import api from '../../api'
+import Cookies from 'js-cookie'
+import * as types from '../mutation-types'
+
+// initial state
+const state = {
+ user: null,
+ token: Cookies.get('token')
+}
+
+// mutations
+const mutations = {
+ [types.SAVE_TOKEN] (state, { token, remember }) {
+ state.token = token
+ Cookies.set('token', token, { expires: remember ? 365 : null })
+ },
+
+ [types.FETCH_USER_SUCCESS] (state, { user }) {
+ state.user = user
+ },
+
+ [types.FETCH_USER_FAILURE] (state) {
+ state.token = null
+ Cookies.remove('token')
+ },
+
+ [types.LOGOUT] (state) {
+ state.user = null
+ state.token = undefined
+ state.impersonatorToken = undefined
+
+ Cookies.remove('token')
+ }
+}
+
+// actions
+const actions = {
+ fetchUser ({ commit }) {
+ // const user = await api.fetchUser()
+
+ // if (user) {
+ // commit(types.FETCH_USER_SUCCESS, { user })
+ // } else {
+ commit(types.FETCH_USER_FAILURE)
+ // }
+ }
+}
+
+// getters
+const getters = {
+ authUser: state => state.user,
+ authToken: state => state.token,
+ authCheck: state => state.user !== null
+}
+
+export default {
+ state,
+ mutations,
+ actions,
+ getters
+}
diff --git a/resources/assets/js/store/mutation-types.js b/resources/assets/js/store/mutation-types.js
new file mode 100644
index 0000000..d8d381d
--- /dev/null
+++ b/resources/assets/js/store/mutation-types.js
@@ -0,0 +1,6 @@
+// auth.js
+export const LOGOUT = 'LOGOUT'
+export const FETCH_USER = 'FETCH_USER'
+export const SAVE_TOKEN = 'SAVE_TOKEN'
+export const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS'
+export const FETCH_USER_FAILURE = 'FETCH_USER_FAILURE'
diff --git a/resources/assets/js/utils/router.js b/resources/assets/js/utils/router.js
new file mode 100644
index 0000000..86dcd76
--- /dev/null
+++ b/resources/assets/js/utils/router.js
@@ -0,0 +1,104 @@
+import Router from 'vue-router'
+
+/**
+ * Create a router instance.
+ *
+ * @param {Array} routes
+ * @return {Router}
+ */
+export default function router (routes) {
+ const router = new Router({
+ routes,
+ scrollBehavior,
+ mode: 'history'
+ })
+
+ router.beforeEach((to, from, next) => {
+ const components = router.getMatchedComponents({ ...to })
+
+ if (components.length) {
+ setTimeout(() => {
+ router.app.$loading.start()
+ router.app.setLayout(components[0].layout || '')
+ }, 0)
+ }
+
+ next()
+ })
+
+ router.afterEach((to, from) => {
+ setTimeout(() => router.app.$loading.finish(), 0)
+ })
+
+ return router
+}
+
+const authenticated = false
+
+/**
+ * Add the "authenticated" guard.
+ *
+ * @param {Array} routes
+ * @return {Array}
+ */
+export function authGuard (routes) {
+ return guard(routes, (to, from, next) => {
+ if (authenticated) {
+ next()
+ } else {
+ next('/login')
+ }
+ })
+}
+
+/**
+ * Add the "guest" guard.
+ *
+ * @param {Array} routes
+ * @return {Array}
+ */
+export function guestGuard (routes) {
+ return guard(routes, (to, from, next) => {
+ if (authenticated) {
+ next('/')
+ } else {
+ next()
+ }
+ })
+}
+
+/**
+ * @param {Array} routes
+ * @param {Function} guard
+ * @return {Array}
+ */
+function guard (routes, guard) {
+ routes.forEach(route => { route.beforeEnter = guard })
+
+ return routes
+}
+
+/**
+ * @param {Route} to
+ * @param {Route} from
+ * @param {Object|undefined} savedPosition
+ * @return {Object}
+ */
+function scrollBehavior (to, from, savedPosition) {
+ if (savedPosition) {
+ return savedPosition
+ }
+
+ const position = {}
+
+ if (to.hash) {
+ position.selector = to.hash
+ }
+
+ if (to.matched.some(m => m.meta.scrollToTop)) {
+ position.x = 0
+ position.y = 0
+ }
+
+ return position
+}
diff --git a/resources/assets/scss/_variables.scss b/resources/assets/scss/_variables.scss
new file mode 100644
index 0000000..4605df6
--- /dev/null
+++ b/resources/assets/scss/_variables.scss
@@ -0,0 +1,48 @@
+// Body
+$body-bg: #f5f8fa;
+
+// Fonts
+$fa-font-path: '/fonts';
+
+// Cards
+$card-cap-bg: #fbfbfb;
+$card-border-color: #e8eced;
+
+// Borders
+$border-radius: .125rem;
+$border-radius-lg: .2rem;
+$border-radius-sm: .15rem;
+
+// // Borders
+// $laravel-border-color: darken($body-bg, 10%);
+// $list-group-border: $laravel-border-color;
+// $navbar-default-border: $laravel-border-color;
+// $panel-default-border: $laravel-border-color;
+// $panel-inner-border: $laravel-border-color;
+
+// // Brands
+// $brand-primary: #3097D1;
+// $brand-info: #8eb4cb;
+// $brand-success: #2ab27b;
+// $brand-warning: #cbb956;
+// $brand-danger: #bf5329;
+
+// // Typography
+// $font-family-sans-serif: "Raleway", sans-serif;
+// $font-size-base: 14px;
+// $line-height-base: 1.6;
+// $text-color: #636b6f;
+
+// // Navbar
+// $navbar-default-bg: #fff;
+
+// // Buttons
+// $btn-default-color: $text-color;
+
+// // Inputs
+// $input-border: lighten($text-color, 40%);
+// $input-border-focus: lighten($brand-primary, 25%);
+// $input-color-placeholder: lighten($text-color, 30%);
+
+// // Panels
+// $panel-default-heading-bg: #fff;
diff --git a/resources/assets/scss/main.scss b/resources/assets/scss/main.scss
new file mode 100644
index 0000000..3acbc68
--- /dev/null
+++ b/resources/assets/scss/main.scss
@@ -0,0 +1,26 @@
+// Fonts
+@import url(https://fonts.googleapis.com/css?family=Raleway:300,400,600);
+
+// Variables
+@import 'variables';
+
+// Bootstrap
+@import 'node_modules/bootstrap/scss/bootstrap';
+
+@import 'node_modules/font-awesome/scss/font-awesome';
+
+.navbar {
+ border: 1px solid #d3e0e9;
+ background-color: darken(#fff, 3%);
+}
+
+.btn {
+ cursor: pointer;
+}
+
+.page-enter-active, .page-leave-active {
+ transition: opacity .3s
+}
+.page-enter, .page-leave-active {
+ opacity: 0
+}
diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php
new file mode 100644
index 0000000..e5506df
--- /dev/null
+++ b/resources/lang/en/auth.php
@@ -0,0 +1,19 @@
+ 'These credentials do not match our records.',
+ 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
+
+];
diff --git a/resources/lang/en/pagination.php b/resources/lang/en/pagination.php
new file mode 100644
index 0000000..fcab34b
--- /dev/null
+++ b/resources/lang/en/pagination.php
@@ -0,0 +1,19 @@
+ '« Previous',
+ 'next' => 'Next »',
+
+];
diff --git a/resources/lang/en/passwords.php b/resources/lang/en/passwords.php
new file mode 100644
index 0000000..e5544d2
--- /dev/null
+++ b/resources/lang/en/passwords.php
@@ -0,0 +1,22 @@
+ 'Passwords must be at least six characters and match the confirmation.',
+ 'reset' => 'Your password has been reset!',
+ 'sent' => 'We have e-mailed your password reset link!',
+ 'token' => 'This password reset token is invalid.',
+ 'user' => "We can't find a user with that e-mail address.",
+
+];
diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php
new file mode 100644
index 0000000..9608bc2
--- /dev/null
+++ b/resources/lang/en/validation.php
@@ -0,0 +1,119 @@
+ 'The :attribute must be accepted.',
+ 'active_url' => 'The :attribute is not a valid URL.',
+ 'after' => 'The :attribute must be a date after :date.',
+ 'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
+ 'alpha' => 'The :attribute may only contain letters.',
+ 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
+ 'alpha_num' => 'The :attribute may only contain letters and numbers.',
+ 'array' => 'The :attribute must be an array.',
+ 'before' => 'The :attribute must be a date before :date.',
+ 'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
+ 'between' => [
+ 'numeric' => 'The :attribute must be between :min and :max.',
+ 'file' => 'The :attribute must be between :min and :max kilobytes.',
+ 'string' => 'The :attribute must be between :min and :max characters.',
+ 'array' => 'The :attribute must have between :min and :max items.',
+ ],
+ 'boolean' => 'The :attribute field must be true or false.',
+ 'confirmed' => 'The :attribute confirmation does not match.',
+ 'date' => 'The :attribute is not a valid date.',
+ 'date_format' => 'The :attribute does not match the format :format.',
+ 'different' => 'The :attribute and :other must be different.',
+ 'digits' => 'The :attribute must be :digits digits.',
+ 'digits_between' => 'The :attribute must be between :min and :max digits.',
+ 'dimensions' => 'The :attribute has invalid image dimensions.',
+ 'distinct' => 'The :attribute field has a duplicate value.',
+ 'email' => 'The :attribute must be a valid email address.',
+ 'exists' => 'The selected :attribute is invalid.',
+ 'file' => 'The :attribute must be a file.',
+ 'filled' => 'The :attribute field is required.',
+ 'image' => 'The :attribute must be an image.',
+ 'in' => 'The selected :attribute is invalid.',
+ 'in_array' => 'The :attribute field does not exist in :other.',
+ 'integer' => 'The :attribute must be an integer.',
+ 'ip' => 'The :attribute must be a valid IP address.',
+ 'json' => 'The :attribute must be a valid JSON string.',
+ 'max' => [
+ 'numeric' => 'The :attribute may not be greater than :max.',
+ 'file' => 'The :attribute may not be greater than :max kilobytes.',
+ 'string' => 'The :attribute may not be greater than :max characters.',
+ 'array' => 'The :attribute may not have more than :max items.',
+ ],
+ 'mimes' => 'The :attribute must be a file of type: :values.',
+ 'mimetypes' => 'The :attribute must be a file of type: :values.',
+ 'min' => [
+ 'numeric' => 'The :attribute must be at least :min.',
+ 'file' => 'The :attribute must be at least :min kilobytes.',
+ 'string' => 'The :attribute must be at least :min characters.',
+ 'array' => 'The :attribute must have at least :min items.',
+ ],
+ 'not_in' => 'The selected :attribute is invalid.',
+ 'numeric' => 'The :attribute must be a number.',
+ 'present' => 'The :attribute field must be present.',
+ 'regex' => 'The :attribute format is invalid.',
+ 'required' => 'The :attribute field is required.',
+ 'required_if' => 'The :attribute field is required when :other is :value.',
+ 'required_unless' => 'The :attribute field is required unless :other is in :values.',
+ 'required_with' => 'The :attribute field is required when :values is present.',
+ 'required_with_all' => 'The :attribute field is required when :values is present.',
+ 'required_without' => 'The :attribute field is required when :values is not present.',
+ 'required_without_all' => 'The :attribute field is required when none of :values are present.',
+ 'same' => 'The :attribute and :other must match.',
+ 'size' => [
+ 'numeric' => 'The :attribute must be :size.',
+ 'file' => 'The :attribute must be :size kilobytes.',
+ 'string' => 'The :attribute must be :size characters.',
+ 'array' => 'The :attribute must contain :size items.',
+ ],
+ 'string' => 'The :attribute must be a string.',
+ 'timezone' => 'The :attribute must be a valid zone.',
+ 'unique' => 'The :attribute has already been taken.',
+ 'uploaded' => 'The :attribute failed to upload.',
+ 'url' => 'The :attribute format is invalid.',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute.rule" to name the lines. This makes it quick to
+ | specify a specific custom language line for a given attribute rule.
+ |
+ */
+
+ 'custom' => [
+ 'attribute-name' => [
+ 'rule-name' => 'custom-message',
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap attribute place-holders
+ | with something more reader friendly such as E-Mail Address instead
+ | of "email". This simply helps us make messages a little cleaner.
+ |
+ */
+
+ 'attributes' => [],
+
+];
diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php
new file mode 100644
index 0000000..eb76d26
--- /dev/null
+++ b/resources/views/errors/503.blade.php
@@ -0,0 +1,47 @@
+
+
+
+ Be right back.
+
+
+
+
+
+
+